Where's the book?

Greg Wilson, author of Software Carpentry (blog), asks:

Now, would someone please write “GIS with Python”?

What's my advance?

Seriously, it's a more formidable task than it appears. The Python and GIS landscape is rapidly evolving and segregated. Unlike bioinformatics or natural language processing (with Python programming books listed in Greg's post), GISville is a company town. To most GIS programmers "GIS with Python" means ESRI software scripting now with Python instead of Avenue or AML. If there isn't an ESRI Press book on scripting with Python already, there will be soon, but it'll be bound to proprietary software. Software that's "free" to use in the U's computer lab, but not free to use out in the real world or on the internets. And it won't cover free and open source GIS tools.

The seedy side of GISville could be tackled in an "Open Source GIS with Python", perhaps, but even this is a fragmented place with many competing platforms. The are programmers who script GIS tasks with Python on a MapServer/GDAL + SWIG platform. There are programmers who script GIS tasks with Python on a different Qt + SIP platform. We've even got our own Django-Pylons type divide on the standard Python platform. How would one synthesize the different Python software and practices? I don't see how, but maybe I'm lacking the right perspective.

Update (2009-10-18): See http://groups.google.com/group/python-gis-sig


Re: Where's the book?

Author: Matthew Perry

Instead of synthesizing all those disparate uses into a typical book, how about a collection of chapters on each, edited together to form a comprehensive overview of the python spatial ecosystem? This way you could have the best authors tackle their primary subject and still provide the big picture.

It could be called "Geospatial Python: Overlapping approaches to spatial programming" :-)

Re: Where's the book?

Author: Eric Wolf

Personally, I'd love to see a Python GDAL/OGR-oriented book that implemented basic geoprocessing. Essentially a "here's how to do geoprocessing without ESRI". It would also be easier to introduce more advanced programming concepts. I've found that GISers and Geographers tend to get stuck in the learning curve when using Python with the arcgisscripting module. The learn to do loops and manage simple variables but frequently have trouble seeing the need for objects and modules.

Ironically, I've found myself temporarily without an ESRI license for the first time in about 10 years. So the project I'm working on will be done in straight Python+OGR. It's actually a little annoying because I'm having to write a slew of computational geometry routines (I know, there are libraries like CGAL, but I like using my own objects).

I'd be game to help write a book...

Re: Where's the book?

Author: Sean

OGR? Here's an example of my perspective problem: I've developed enough loathing for the ogr.py API (since years) that I've written WorldMill and blogged a lot about using it. It prompted Howard to make ogr.py better, but I feel like my Shapely, WorldMill, Rtree stuff remains more usable.

Re: Where's the book?

Author: Sean

I'm on the loosely-coupled "Pylons" side of the divide, if it's not obvious.

Re: Eric

Author: Keith


Have you tried Spatialite? It has the core spatial functions - intersect, union, distance, length, centroid, etc. It is so easy to use and has a nice GUI to view the spatial data. The commands are incorporated in SQL. The tutorial is good too.


Re: Where's the book?

Author: Sean

Keith: Spatialite is a neat data store, but only that. What you use to process data after you take it out of the store (and before you store the results) is the question.

Re: Where's the book?

Author: Peter


Re: Where's the book?

Author: Sean

Peter: I like declarative programming, and there are some neat options to combine and balance Python and XSLT in lxml's extension elements, but I imagine that the declarative style works best for geoprocessing in configuring complex pipelines of data processing modules that would be written in Python. Maybe like Paste Script wires up WSGI pipelines.

Re: Where's the book?

Author: Peter


There's no doubt (in my mind) the heavy lifting in terms of geoprocessing needs to be done by an indexed datastore, hopefully accessible via spatial XQuery/XPath :). There are good current benefits in terms of simplicity, portability and ownership of your code, to thinking about low-volume, high-fidelity geoprocessing in pipelines, as you say. Some pipeline alternatives for such pipelines may in the future include


, and


. To provide sufficient performance, a geospatial implementation perspective needs to be baked in, something I would like to see.



Re: Where's the book?

Author: Keith

Sean, Spatialite just a datastore? I use pysqlite to script and create UserDefinedFunctions (UDF) to extend and reuse functionality. Sqlite is rock solid and fast, with a 2 terabyte database size limit on 32bit machines. All this functionality for free - Transactions, Virtual tables, Spatial indexes, attribute indexes, projections, overlay commands (clip,erase,intersect), aggregation, simplification, routing. For just a data store it sure sounds like a geospatial engine. The datastore aspect is compelling as well. You can store multiple geometry types in the same table. A shapefile will only hold a single geometry type. You can also have multiple geometry columns in a single Sqlite table - various projections, for example or you could store parcels as various geometries - rectangular lot, building footprint, property centroid. The business data is easier to manage in a database too. Gotta love it.

Re: Where's the book?

Author: Sean

Relational databases have a large, but not limitless set of uses. If you're going to process non-relational data such as documents or less structured data, you'll need a general purpose programming language and environment. For example, you're certainly using a general purpose language already (maybe even Python) to model data so that it can be loaded into your database. I think maybe you confuse me for a "NoSQL" partisan. I simply think an RDBMS is better suited to storing models than to doing all kinds of modeling and data processing.

Back to the topic of Python books: it wasn't my intention to throw "stop energy" at a book effort, but to point out that "Python and GIS" is a messy subject and potential readers are somewhat segregated in different camps. I'm hugely in favor of more, excellent narrative documentation.

Re: Where's the book?

Author: keith

I vote for starting a wiki instead of publishing a book. More people can access a wiki via the internet and it is easier/cheaper to maintain and update a wiki. A book might be out of date in a few years as software is updated. There is a huge variety of open source GIS tools that people use. I'd like to see work flow diagrams, recipes, code snippets, etc how real work is getting done. There is also IronPython (dotnet)and Jython (java) to consider along with Python.

Re: Where's the book?

Author: julia

A "Geospatial Python" wiki with evolving content from geospatial python experts that covers many of the various geospatial python implementations, including interacting with spatial data stores, would be a very welcome thing indeed to many people who are not geospatial python experts but need some good resources and examples - so we won't keep getting stuck in that learning curve....

Don't know that I'd characterize Open Source GIS as "the seedy side" of GISville. I think of it more as the "Company Town" side of GISVille being the snooty gated community where entry is controlled both by the size of one's bank roll and one's desire to pay a high entry fee for the "privilege" of feeling like one is part of some exclusive, superior society. The superiority thing is not true, but the "Company" really excels in marketing, so a lot of people believe the hype. The problem is that inside the gated community, the "Company Way" is the only allowed way to do things. Like an H.O.A. gone completely wrong :)

Many of us (who have been forced to live in the gated community for many years by our employers in the public sector) would like to start learning several different ways of doing similar tasks in GIS with python, and not limit ourselves to a single toolset. That same old "geoprocessing" hammer doesn't always do such a great job :) Knowing more than one way to solve the problem, or how to use more than one tool is a big help when deciding what method makes the most sense to use in any given situation. The aforementioned wiki would be very helpful to a lot of people as a learning aid and in helping to compare and contrast the benefits or drawbacks of employing different approaches.

On web sanity

Stefan Tilkov, who has written an excellent REST introduction and an analysis of REST anti-patterns has some criticism for enterprise web apps that applies equally well to "GeoWeb" apps:

In other words: Many web frameworks, especially those within the Java space, try to support the development of desktop applications that are delivered over the Web as opposed to “web sites”, and I believe this idea is deeply flawed: Any Web application should be measured against the criteria that are used to judge web sites.

I think this goes for the "GeoWeb" too. We're delivering too much desktop GIS over the web. It's a point made also by Brian Noyle here, though I see Flex, Silverlight, .NET, and MVC as parts of the problem, not the solution.


Re: On web sanity

Author: Tim Bowden

Those links are great thanks Sean. I'm developing a desktop app replacement on the web atm, and that material has clarified some of the issues I've been mulling over. I probably won't get it all right this time around, but I'll certainly get closer than I was going to get.

I've previously looked briefly at the idea of RESTful apps, but not in any great detail or real understanding. Now I am, and it's certainly an interesting journey. The app I'm replacing is definitely very much in the traditional desktop space (with a legacy stretching back all the way from its DOS roots; think reverse engineering very old and poorly documented binary data formats). It doesn't *look* like a candidate to be a 'website' type app, as opposed to a 'desktop app on the web'. The requirements *seem* to point that way, that is until you dissect it bit by bit using a RESTful scalpel. I'm not sure how far I'm going to be able to push this model, either because of limitations in my skill and understanding or limitations in the RESTful model, but I'm keen to see where I can go with this.

It's a good thing this is a relatively simple app, as using a RESTful scalpel for the first time isn't so easy. Old mental models of what desktop apps should look like and how they should behave keep getting in the way. I've still not gone very far on this journey (I've not tried implementing any of this yet; next step!), but so far every issue seems to have been answered by sharpening my RESTful scalpel a little more. I think one of the hardest ideas to come to terms with is the idea of “hypermedia as the engine of application state”. All those 'client side' data structures start to melt into very ephemeral constructions. Implementing that is going to be an interesting experience for sure.

Sean, keep pushing the REST barrow. I'm very much a novice, but from my perspective so far, it *seems* to be a winner, despite the mental difficulty of overcoming deeply ingrained ideas from the desktop environment. Hopefully I'll not be too shell shocked when I come out the other side!

Django goes with grilled chicken

Who says I won't try Django?


I actually liked this winemaker's "Gispy", a rosé blend of Syrah and Grenache, much better. Cinsault ("Django" is 100%) isn't winning me over, yet.


Re: Django goes with grilled chicken

Author: James Fee

I'm scared to think what the Plone blend must taste like.

Re: Django goes with grilled chicken

Author: Sean

"The 2009 Plone is staggeringly complex."

Re: Django goes with grilled chicken

Author: Howard Butler


I think the Plone blend requires that you pay a consultant to open the bottle.

Using git to work on OpenLayers

So that I don't forget, and in the hopes of picking up tips from more experienced users, I'm going to write down my notes on using git to work on OpenLayers without any commit access. OpenLayers is a big project, and enhancing it in a significant way takes time and care. It's worth doing this work within a revision control system. The project has SVN sandboxes, but you can't use them offline (which I've been quite a bit this summer), you have to apply for them (I'm impatient), and my OpenLayers guru is annoyed by them. For these reasons, I've gone with a DVCS, and chose git on account of its nice bridge for Subversion: git-svn.

To begin, clone the OpenLayers trunk. As of today, there have been 9623 revisions. Don't fetch all of them! In this example, I'm going to fetch a small revision range just short of the SVN head so that I can illustrate rebasing later.

$ git svn clone -r 9621:9622 http://svn.openlayers.org/trunk/openlayers
r9621 = 4f62382011af58e8dd8be3b81a817fff80b4f4c4 (git-svn)
Checked out HEAD:
  http://svn.openlayers.org/trunk/openlayers r9621

Now I have cloned OpenLayers and begin by default in a branch named "master". I'll do my work around http://trac.openlayers.org/ticket/1366 in a new branch named "atom".

$ git checkout -b atom
Switched to a new branch 'atom'

I've already produced a patch using the methods I'm noting here, and will apply it to the new branch for the sake of this demo.

$ patch -p1 < atom-format-2.patch
patching file lib/OpenLayers.js
patching file lib/OpenLayers/Format/Atom.js
patching file tests/Format/Atom.html
patching file tests/list-tests.html
$ git commit -a
[atom 315def2] Apply patch from http://trac.openlayers.org/attachment/ticket/1366/atom-format-2.patch.
 4 files changed, 1171 insertions(+), 0 deletions(-)
 create mode 100644 lib/OpenLayers/Format/Atom.js
 create mode 100644 tests/Format/Atom.html

If I were to run "git diff master" I'd recover that same patch. Now, there's a new attachment on my favorite OpenLayers ticket. A patch would have been nice, but a file is better than nothing. I'll create a new branch named "atom-pwr" based on "atom", copy the attached file and overwrite Format/Atom.js in the new branch.

$ git checkout -b atom-pwr
Switched to a new branch 'atom-pwr'
(copy atom.js)

Running "git diff atom" shows me the difference between atom-pwr and atom branches. I'll commit the changes to atom-pwr.

$ git commit -a
[atom-pwr 29ae464] Incorporate pwr's work from http://trac.openlayers.org/attachment/ticket/1366/atom.js.
 1 files changed, 48 insertions(+), 7 deletions(-)

A patch to the OpenLayers trunk incorporating all these changes is generated with:

$ git diff master > atom-pwr-r9621.patch

Now, lib/OpenLayers/Control/GetFeature.js was added in r9623. To keep up with these changes, use git-svn rebase. First on the master branch:

$ git checkout master
$ git svn rebase
        M       lib/OpenLayers/Control/GetFeature.js
r9623 = 3e4282ccb05e9421d8f078893c5c495c55085621 (git-svn)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/git-svn.

And then on the development branch:

$ git checkout atom
$ git svn rebase
First, rewinding head to replay your work on top of it...
Applying: Apply patch from http://trac.openlayers.org/attachment/ticket/1366/atom-format-2.patch.

Now a patch against the current head is generated by:

$ git diff master > atom-r9623.patch

As nothing was changed in the files I'm working on between r9621 and r9623, this patch is identical to the one I started with. Up the new patch goes to the OpenLayers issue tracker to make things as easy as possible for an actual committer.


openlayers on github

Author: whit

Another resource for working with OL using git: ccnmtl is kind enough to mirror OL on GitHub.


SQLAlchemy is the ultimate database toolkit for Python. GeoAlchemy extends it to provide a OGC SFSQL-style spatial ORM. It has an API that looks a bit like Shapely's and the math is also done by GEOS (at least with PostGIS and SpatialLite backends), but using a SQLAlchemy connection to a database instead of libffi and ctypes. I toyed around with SQLAlchemy and Shapely a while back, but Sanjiv's project looks like something that could become very useful for Python and GIS programmers who work with a spatial RDBMS.


Re: GeoAlchemy

Author: Sanjiv Singh

Thanks for the post Sean. I must thank Michael Bayer (author of SQLAlchemy) and Mark Ramm (my mentor) for making GeoAlchemy what it is. I hope the project is able to see some community participation and becomes really useful. :)

3 choices

Author: Paolo

Cool, now Python devevelopers have 3 choices to build spatial applications without starting from scratch: Shapely, GeoAlchemy and GeoDjango.

There is even too much choice! ;-)

Re: GeoAlchemy

Author: Sean

The right amount of choice is a matter of taste. Some people like more, some less.


Andrew Turner quoted me yesterday. The missing context of the quote, which I've linked to several times, is Clay Shirky's essay in praise of evolvable systems, in particular this bit:

HTTP and HTML are the Whoopee Cushion and Joy Buzzer of Internet protocols, only comprehensible as elaborate practical jokes. For anyone who has tried to accomplish anything serious on the Web, it's pretty obvious that of the various implementations of a worldwide hypertext protocol, we have the worst one possible.

Except, of course, for all the others.

You must read it if you haven't already. It's every bit as relevant for today's discussion of the "GeoWeb" as it was for the discussion of the web in 1996.

I'm surprised and disappointed that so much of the discussion at the GeoWeb conference seemed to be stuck on "top-down vs bottom-up" or "80 percent vs 20 percent" or "B2B vs B2C". Of these, the first is the closest approximation of a serious discussion about the nature of the "GeoWeb": is it to be an open, evolvable and therefore always incomplete system, one that demands and rewards innovation -- or is it to be a entire, fixed, thoroughly standardized and unsurprising system? The other two debates are bogus. "'Tastes great' vs 'less filling'".


Re: Evolvability

Author: Terry

"is it to be an open, evolvable and therefore always incomplete system, one that demands and rewards innovation"?

Yes, please.

Data blogging

The Map Butcher writes:

The deadline for the CCIP is approaching and I’ve been lurking on the announcement list and was really interested in this great little application which provides sensor data via Sensor Observation Services. I think the reason that I like this site so much is that it paints a really clear picture of sensor web enablement, and it’s an effective presentation of cross agency data.

It is indeed a neat app, but color me unimpressed (still) by "sensor web enablement". You can't truly call this a clear picture of the OGC's SWE because there's actually nothing done by this application that couldn't be done equally as well using (for example) an Atom + GeoRSS syndication architecture with links to structured data slice resources, perhaps even using GET requests to an SOS service, and javascript to display the data. In fact, I think a syndication-based design does it better: you'd also get discovery, permalinks, paging, synchronization, and potential for reuse of the sensor feeds in feed readers and other applications yet to be imagined.

A sensor is just a robo-blogger, right? Let's connect them to the web with blog technology.


Re: Data blogging

Author: Sean

Via Matt Ball, I've come across SensorBase (http://sensorbase.org/) from CENS (http://research.cens.ucla.edu/). CENS is thinking about sensor blogging too, at least metaphorically; SensorBase doesn't use a feed architecture that I recognize. Still, it sure is fun to see curl used.


Sunday, we spent the entire day out and about in the neighborhood of Saint-Guillaume-le-Désert. It's a well-preserved, captivating (the French say séduisant) medieval village. Touristy, but that's France in the summer. Mainly French tourists, but we heard Spanish, Italian, and English. The centerpiece of the village is the Abbaye de Gellone. Founded in 806 by William de Gellone, a compatriot of Charlesmagne, the Abbey became a popular destination for pilgrims, prosperous, and a home for the arts. There's an excellent multimedia presentation at the Abbey's small museum which describes an ongoing process of laser-scanning the scattered pieces of the Abbey's cloister (many in New York City, Paris, Montpellier) and virtually reassembling the structure and its decorative stone work.

Below is a fun inscription we saw in the museum. I don't read Latin at all. It's quite possible that the text isn't as jolly as the typography.


This photo shows a trail that leaves the village, following a stream into a steep box canyon. Below, there are olives groves, and higher, a research forest. At the the end there is a sequence of narrow waterfalls (dry, now) not unlike what you'd find in the Colorado Plateau, though in limestone instead of sandstone. If I'd had better shoes, I might have tried to scramble up the first one.


Sadly, Google Earth's imagery for the region is low-res only. It's spectacular country. Below Saint-Guillaume-le-Désert are the gorges of L'Hérault, the end of which is spanned by an intact 11th century bridge (shown in images at the end of the French Wikipedia page). Below this bridge, there's an enormous swimming hole and a rocky beach used by hundreds of tourists.

We didn't have our GPS with us, but I have added a few useful points of interest (my first) to OpenStreetMap using Potlach. We'll be returning off-season to do more hiking and fill in some more empty places on the map.

Update (2009-08-10): Here's a photo of the fall:


Made me a bit homesick for the badlands of Utah, it did.


Re: Saint-Guilhem-le-Désert

Author: Clemens Radl

The inscription reads "HIC IACET BLADALDUS PRESBITER QUI OBIIT III ID NOV". This translates to "Here lies the priest Bladaldus who died on November 11". So this was a grave stone.

By the way, Géoportail has some higher-resolution aerial images from this region. See http://is.gd/2aAHK (with an overlay of the excellent IGN map). It's not as easy to navigate as Google Maps, but it offers good images and great maps. On the left hand side you can set the opacity of the map and the image.

Thanks for yet another fascinating sightseeing advice. We are going to spend this year's summer vacation in this area of France, so your reports with photos, descriptions and map links are extremely interesting and valuable.

Re: Saint-Guillaume-le-Désert

Author: Sean

Thanks, Clemens. Now I see that one can get above the dry fall by taking an earlier right branch of the trail :) There are at least 2 afternoons worth of hikes in this valley. And Grotte de Clamouse, which I'm also keen to see, is just down the road. When it's hot, a cave is the only thing that beats a swim in the river.

Here's a tip for visiting in the high season: arrive in the village early. We were extremely lucky to find a parking space in the big lot Sunday at 10:00. Taking the shuttle bus from the big lot at Pont du Diable would be the next best option, I think.

Look me up if you find yourself in Montpellier proper!

Rtree 0.5.0

Rtree 0.5.0 and spatialindex 1.4.0 are out. The major new features are:

  • Better platform parity
  • Efficient bulk indexing
  • Arbitrary dimensionality
  • Improved performance tuning

See Howard Butler's release note for details. The spatialindex lib is beginning to develop a user community of its own. For them, the major new feature is a C API (also used now by Rtree).

It's the imagery, stupid

The reasons we're using KML (which some consider a fork of an early version of GML) instead of GML (version 3) for "GeoWeb" applications have almost nothing to do with the actual merits of these formats. It all comes down to imagery, imagery, imagery. If only there was as much semi-free, global, high-res imagery behind GML 3 applications as has been deployed for Google Earth, we'd all be deliriously in love with GML. Stefan Geens and Frank Taylor would be tirelessly blogging about all the awesome possibilities of GML. Google would have indexed half a billion GML documents. I might even write a Python GML library. People aren't doing things with KML that you couldn't do with GML. It's all about the free-ish imagery on the KML platform.

(with apologies to James Carville)


Re: It's the data, stupid

Author: Paul Ramsey

Same thing holds for the GMaps APIs and Google Earth as a piece of software. The truly innovative thing Google did was not the technology it was (just as in their search business) the business model shift: from direct payment for data to free data with indirect payment via advertising. That their software was pretty cool was icing on the cake, but it was all that free(ish) data that won the day.

Re: It's the imagery, stupid

Author: Matt Giger

It's sad how the geospatial community is so beholden to Google, who can yank the "free maps" rug out from under anyone at any time.

Re: It's the imagery, stupid

Author: Ron Lake

I think it was a convergence of multiple factors - the fact of global data (especially images) - the wars in Iraq on CNN - the realization by Google that people wanted to see themselves and tell stories - and a good execution on the side of the Earth Browser and use of KML for control and visualization.

Since GML has a very different intent, I don't think we would be focused on billions of GML files. GML was never intended for visualization nor browser control (as in "look here") - so is not intended for end users. It is more intended for under the hood plumbing - communicating between databases - transporting eospatial transactions and the like. I think GML has expanded in a number of domains from climate science to city modeling to commercial aviation and even into the bed rock (IETF) of the Internet itself. I don't think its play is over by any means - maybe just at the start. GML and KML play complementary roles and if one wants a GeoWeb that is more "web like", understanding on building on that complementarity is even more important.

Author: Ron Lake

Actually I would not agree with this statement. While one could have written KML in GML (and not the other way around) - that would still be an abberration of the intent of GML. GML is intended to capture geospatial content quite apart from HOW it is presented. KML is all about presentation and browser control. KML is not very useful where we are mainly concerned with machine to machine communication. GML is not all that useful in communication with people. True there was a component called default styling and some good innovations around things like "topology styling" this was never central to GML.

Re: It's the imagery, stupid

Author: Matt Priour

In the same vein, I would really like to see Google Maps API (which the others will follow) read GeoJSON data directly. I know it is an almost trivial javascript processing task to translate those into Google Map features, but having native support would greatly boost the "importance" of that format.

As it is now, clients that want to generate dynamic maps in Google Map have a strong preference for KML or GeoRSS. GeoRSS as a format is a mess since one can use any combination of one of the RSS syndication protocols (RSS 1.0, RSS 2.0, Atom) combined with one of the geometric representations formats. At least Google Maps shows a preference for Atom with GML for GeoRSS but any XML based format can be parsed and used.

Re: It's the imagery, stupid

Author: Eric Wolf

Maybe I'm just a paleo at heart - but I find it more startling that almost all of this imagery is in a Mercator projection (Euro-centric, global north land sizes enlarged, global south diminished, Poles fail). Sure, if you're trying to sail from Spain to Florida, it's a damned good projection. But there aren't many other redeeming qualities.

The GeoWeb is constantly imposing de facto standards that those of us labelled paleo cringe over.

Re: It's the imagery, stupid

Author: Ian Painter

More and more people assume that the GeoWeb is something that only lives in the browser, I don't agree with this and Ron has a point. People 'dis' GML for being too complex for the browser, but its not really designed for that. Whilst B2C is clearly all about the browser, B2B isn't going to happen there and GML is more popular than ever for B2B data exchange. Yes KML solves the 80/20 but don't underestimate how important that 20% can be. In my mind to get 100% GeoWeb you need 80% B2C and 20% B2B. That's KML, GML, REST and SOAP living in harmony.

Re: It's the imagery, stupid

Author: Brian Hamlin - darkblue_b

well, it *is* the imagery, and more ! Twenty-five years ago, a mouse was a specialized instrument, and I recall vividly the PC crowd bemoaning "graphics" as a productivity killer.. User interface, accessibility, ease of adoption, utility, ubiquity and transferability of skills and work product all play a part in the adoption of new technology.

At the

5th International Symposium on Digital Earth

(my first) two years ago, I realized that Geo Browsers was something whose time had come, on a number of levels. I have no qualms about representing KML to the old-timers - and I have gotten some suspicious stares here and there.. but listen to this - its not that I fear our future with computers, at this point I fear our future *without* computers. (apologies to Isaac Asimov)

Re: It's the imagery, stupid

Author: Terry Stigers

@Eric Wolf: Thanks. From one caveman to another.