I’ve been playing around with a cool, real-time, client-side code driven cloud database called Firebase for the last while, and here is one of the projects that came out of it.
There is a local need to identify the streets and other routes that are actually used by cyclists in Prince George, BC (not just “where are the bike routes?”). That sounds like a heatmap to me. Using jQuery Mobile (frontend), Google Maps API (maps), and Firebase (backend), the user can add a direction line to the map (“Add Route” button), modify the directions if they do not show the desired route (drag the route or end points), and save the route (“Submit Route” button). Once the route has been saved, the heatmap will update to reflect the addition. And the cool part is: it will update everyone else’s view in real time, which is important because I know this will go viral. Also cool, I didn’t write a single line of server-side code.
Go ahead and play with the map – add as many lines as you want. I’ve set it so the directions default to Prince George, but you can drag and submit them wherever you want. The biggest limitation of the map is that the directions are converted to points to feed into the heatmap, so in the end it is really a heatmap of most popular corners, not routes.
Disclaimer: this seems to work fine in my versions of Chrome and IE (surprise), but not my iPad’s Safari. Please let me know if you have any insight.
I’m not brewing beer this week, but I probably will get a batch started next weekend. One of the key parts of brewing is chilling the boiled wort (pre-beer) to yeast pitching temperature, quickly. Up until a few days ago, I was able to accomplish this by putting the wort pot in a snow bank in my front yard. But, with the arrival of spring, I needed to come up with a new plan.
This morning, I started researching other methods for cooling the wort, and decided to build an immersion wort chiller. Basically, cold tap water runs from a vinyl tube, through a copper coil (25′ long, 1/2″ OD), and deposits the water (and heat from the hot wort) down the drain. With the help of my plumber buddy’s tradesman’s discount, I was able to collect the necessary materials for $31.17 + tax. You can watch an exciting video of the wort chiller practicing for duty here.
Received a hard drive full of imagery today. Tiles in two UTM zones, luckily specified in file name. Lots of folders. No projections defined. Here’s how to do it.
import os, arcpy
inFolder = r"ROOT PATH OF ALL IMAGERY"
folders = os.walk(inFolder)
sr9 = arcpy.Describe(r"PATH TO FILE ALREADY IN ZONE 9").spatialReference
sr10 = arcpy.Describe(r"PATH TO FILE ALREADY IN ZONE 10").spatialReference
for folder in folders:
for file in folder:
if 'U10W84' in file:
arcpy.DefineProjection_management(os.path.join(folder, file), sr10)
elif 'U9W84' in file:
arcpy.DefineProjection_management(os.path.join(folder, file), sr9)
Slow afternoon = time to play with Google Maps API. Lots of people bash Google and other slippy maps for using web mercator. Yes, it is distorted, but aren’t they all? Personally, I don’t have a serious problem with the distortion – I know it’s there. The “danger,” if there is one, is that some people don’t know mercator is distorted and go about their day thinking Greenland is the same size as South America (the horror). So, to help remind us all that mercator distorts area, here is a Google Maps API-based Tissot Indicatrix showing what happens to a 500km circle placed anywhere on the map (they are all 500km radius). And I do mean anywhere – you can drag the circles. Watch them change size, and get all funky at the poles.
UPDATE: this post has been featured in Google Maps Mania!
I’m sure it’s been done before, but I made this minimalist GPX viewer today (relying heavily on the gpxviewer library). As long as you have a File API compliant browser (apparently not any version of IE), you should be able to load a GPX file from the top button, and it will load onto the map. Next step will be to save the GPX file to a shapefile.
Arduino parking countdown prototype
Since there’s only 2-hour parking around my work, I’m too cheap to buy a monthly parking pass, and I had an Arduino Uno waiting for a project, I made a timer that chirps two hours after the reset button is pressed (video with finished case here, finished timer counts to two hours). The code and circuit design are quite simple, so I’m not going to bother posting them unless there’s some interest – if you’re looking for examples like this one, you should probably explore the Arduino Playground.
Lesson learned: data types matter. It took me longer than I’d like to admit to figure out why I couldn’t count higher than 32 seconds in milliseconds with an int (hint: ints range from -32,768 to 32,767).
Well, I’ve been on a bit of a hiatus from this blog, thanks in large part to switching jobs and cities. But, I’ll try to fit posts in here and there as time allows.
Since ArcGIS licenses come at a premium (i.e. not everyone gets one), I am often tasked with performing file conversions that are difficult to perform outside the ArcGIS environment (and without the help of arcpy). So, in my quest for efficency (or laziness, whichever you choose), I am attempting to write a script that will take polygon shapefiles, convert to one line shapefile, and output the lines to a GPX file for upload to a GPS unit. The ultimate goal is to use py2exe to make a standalone application in which users can upload their own polygon shapefile and output a GPX file, and leave me out of it (not that I mind, but I’d rather focus on analysis).
Here’s what I’ve got so far. It deconstructs a polygon shapefile to individual vertices and outputs a line shapefile, using the pyshp library. Next steps involve installing GDAL, figuring out how to convert the shapefile to GPX, and packaging it all up with py2exe for distribution.
# import the shapefile library
# path to input polygon shapefile
infc = shapefile.Reader(r"C:\users\dwiens\GIS_Data\testpoly")
# create a shapefile writer
outfc = shapefile.Writer(shapefile.POLYLINE)
# turn geometry/attribute autoBalanace on
outfc.autoBalance = 1
# add a field, any field
# get the input geometries
shapes = infc.shapes()
# create empty arrays to hold line parts and vertices
linePoints = 
lineParts = 
# loop through shapes
for shape in shapes:
# loop through each vertex
for point in shape.points:
# add each vertex to array
# add vertex array to shape array
#empty the vertex array, move to next shape
linePoints = 
# encode coordinates as a line
# add blank value as a record
# save the shapefile