• Wasted Day

    It’s been pretty rainy, and cold again, for the past few days. The sun is out now, but it’s still a bit chilly; I just came back in from a short yard work stint, which has been the only thing I did so far today — no Canal Museum, no ride…

    Yesterday I went over to CAT and did some work on b-i-l Ray’s bike, a 5-speed Raleigh (circa 1974) which is now almost roadworthy, and the past few days I’ve been grinding through a cleanup of my giant mail pile, tossing or filing things as necessary, paying bills as I find them. Both of these were exhausting work, my brain was fried, and I did something I thought would be restful: I watched the new NetFlix series Altered Carbon.

    Big mistake. I loved the book(s), and found the dumbed-down TV version somewhat unsatisfying, but I couldn’t stop watching. I ended up binge-watching five episodes last night, and two more this morning. Plenty of violence, and sex (or at least nudity), and the basic outline of the story is still there even if the backstory has been uh, altered. I was up past midnight watching, so maybe that’s why I was so tired today.


  • And A Couple More

    Friday’s ride at South Mountain in Emmaus was awesome, though it started late in the day with some missed connections. (We were all together at the trailhead by 4:30 and riding soon after, so it all worked out.) Greg, Ken M, and Mike K and his brother Mark. The day was pretty warm for a change, and I was puffing and sweating but I thought I rode well enough, especially on unfamiliar and sometimes difficult terrain.

    Saturday I rode in to the Museum again for the annual volunteer cleanup day at the park. Unfortunately, I got my signals crossed (maybe a theme for the weekend), and arrived at the end… Facilities guy Scott set me up with some work for me before he left though, so I got in my share: about about four hours of sanding benches. I only got four done, and part of a fifth, but it was hot, dirty work; when I left for the ride home my butt was dragging…

    We went to Ted & Mary Lou’s house last night — after my too-short nap — to celebrate their daughter Lily’s marriage. A fun evening with a lot of really nice people, but it was also an early night: we were home and in bed by 10:30. The evening, which started out just on the good side of “too warm,” had already turned chilly on our walk home. Now it’s cold and blustery out, and we’re expecting rain.


  • A Coupla Rides

    I’ve been getting out a lot more as the weather gets nicer…

    Last Thursday I took a “mapping ride” on the Iguana, down the South Bethlehem Greenway and over into the Intermodal Facility, aka Commerce Center Boulevard. There’s been a lot of construction over there, new buildings as well as new roads, and there has also been a persistent (and likely erroneous) OpenStreetMap note connected with that location, that I wanted to clear up but I didn’t know the area at all. So off I went, to see it all firsthand and gather data. Total ride mileage: 14.8 miles in just over an hour and a half.

    The result? After the ride I was able to update the map with several new roads and buildings, including the extension of Commerce Center Blvd into a huge, newly constructed loop. (I’d never been back there, and was amazed at the size of the place and its buildings.) I also updated the Greenway, which is now no longer under construction, and added a new access point.

    On Friday I did a towpath ride, 23.5 miles in 2:04.

    Wissahickon was on Saturday. I half expected this ride to be canceled because the weather was supposed to be bad (one reason for Friday’s ride), and the day started cold and a bit sleety, but things rapidly improved… I rode down with Lou and Scott, and we met Jason and Mike down there. I have not been to Wissahickon for mountain biking in probably 20 years, had no idea what to expect, and ended up having a hilly, rocky blast. We all felt good and rode well, especially for how early in the season it was — weather-wise at least, if not according to the calendar. Ride stats: 16 miles in just about 4 hours.

    Monday was another Towpath ride, and yesterday I rode the towpath to my Canal Museum gig — on my ride home I was running on fumes.

    Today is a rest day, and it’s raining anyway, and tomorrow I may ride with a few friends at South Mountain in Emmaus.


  • Double Nickels

    Happy Birthday to me! Yesterday was my birthday, and I’m now 55 years young. Dinner and cake at Mom & Dad’s on Sunday, drinks with friends last night, a good birthday weekend all around.


  • Gautama’s Gizmo Time

    Posted on by Don

    Today I’m writing at Lit, the relatively new coffee shop in Southside, while hanging with Anne. I could say I’m now living the dream: laptop and wi-fi in a caffienated third space, except that the dream actually is a bit noisier  than I would have liked…

    Sometimes I think I’m drawn to tech more because I like the idea of tech — the toys and gizmos, smartphones and memory sticks — like the feeling of being in Staples or another stationary store. All that paper! The desks! The organizers! Actually getting the new stationary, or learning the tech, leaves a hollow, let-down feeling, like after all your Christmas presents have been opened, or like a sugar-buzz come-down.

    My latest tech acquisition — my latest trip around the tech wheel of samsara — is a WordPress security plug-in. I’d noticed a lot of traffic on the site, which is cool, but the traffic was basically to my login page — not so cool. The plug-in I installed blocks IP’s that try to login with the wrong user name or password, plus a few other things, and I spent a good part of last night watching it catch and block malicious users. I know I’ll eventually get bored and achieve that come-down, but for now it’s hypnotic…


  • Springtime! Happy Easter!

    Posted on by Don

    I’m sitting at the Bethlehem Library right now — I was planning to maybe ride today but last night’s wet spring snow put the kibosh on that. I felt a bit cooped up and wanted to get out of the house for a bit, so I thought I’d check the new coffee shop (the Church Street Market) across the way but it’s closed on Mondays. I’ll be meeting Anne and maybe Deb at Wise Bean in a bit, but I had a hankering to do the laptop-and-café thing… Oh well, the library works.

    We had a fairly hectic weekend: Friday night was the Adult Easter Egg Hunt at Anne’s niece’s house, Saturday was a Seder at Toby & Erika’s, and yesterday we did an Easter brunch. I got in a ride on Saturday morning, and I’m glad I did since conditions were really good, and it looks like they won’t be good again for a little while. Spring’s coming, it’s just taking its time.

    Fun with Computer Maintenance: I got fed up with Adblock and installed uBlock Origin instead. Better, faster, less intrusive.

    PostGIS Fun: I merged all the bus routes into one GeoJSON file, then loaded them into the database. I then took that table and broke it into two others: one containing the bus stops, with their names, reference numbers,  OSM attributes, and geometries, and a bridging table (sans geometry) containing fields for the bus stop reference, route and stop order for all routes. Some new ideas: “select distinct on” and “window functions.” Works like a charm!

    Off to the Wise Bean…


  • Digging-Out Diary

    I kind of fell into the same trap as before — leaning too heavily on categorization for my posts — and am now stuck, playing catch-up with things I wanted to talk about that really didn’t warrant their own posts. So…

    Cali Weekend: I finally managed to go skiing this year. Julie G had an extra ski pass and a Friday off, so we went up for a morning on the slopes at Blue Mountain. She’s a bit of  a neophyte (or maybe more like “haven’t skied since college”), and was more comfortable on the easier slopes, and I was too, to tell you the truth. We did two each on the Burma Road and Paradise trails, then I did two on the intermediate Lazy Mile, and we called it a day. It was surprisingly fun, especially since I had been worried beforehand, about getting hurt or whatever.

    The next day I did a towpath ride, going the whole length to the waterfall in Easton, and on Sunday Anne and I rode the towpath to Easton for brunch at Two Rivers.

    That was two weekends ago. The weather has been pretty crappy since then, but we did manage to get out, in one heavy spring snow, to attempt some cross-country skiing: too warm, and the snow was too wet. Oh well, at least we tried…

    Reading: I read Ann Leckie’s new novel Provenance , set in the same story universe as her Imperial Raadch trilogy (but not within the Raadch itself). Fast paced and fun — especially for a book about the authenticity of venerated historical objects — I’d recommend this to anyone who liked her trilogy.

    I also finished Hilary Mantel’s Bring Up The Bodies, her second novel about Thomas Cromwell, advisor to Henry VII. This one picks up where the first left off (at the execution of Thomas More), and continues through to the execution of Henry’s second wife, Ann Boleyn. It was just as absorbing, but seemed to move a bit slower than the first.

    Next up was The Discovery of Middle Earth: Mapping the Lost World of the Celts, by Graham Robb. It had an interesting premise: the Celts were more sophisticated than we realize, and had a pretty advanced navigation system, based on astronomy and a system of survey points, which they used to build roads and locate their cities. That was the theory; in practice the book was a rambling mess, full of very enjoyable digressions and oddly useless maps and diagrams, that attempted to tell the story of the Celts. (The book reminded me, more and more as I plowed through it, of Robert Graves’s The White Goddess, and not in a good way.) There were parts I really liked, but I struggled to finish it.

    And finally, I’m in the middle of The Selected Works of T.S. Spivet, a novel by Reif Larsen. This is the story of Tecumseh Sparrow Spivet, a 12-year-old prodigy (mapmaker, scientific illustrator) living on a ranch in Montana, who wins an award and a job offer from The Smithsonian Institution — who don’t realize he’s a child — and takes off for Washington DC via freight train. That’s as far as I got, but so far the story is compelling and multi-layered and, despite appearances, not a Young Adult novel.

     


  • Data Cleanup Automation Fun

    I’m still playing with LANTA’s bus routes data, girding myself for — eventually — adding the bus routes into OpenStreetMap, but I recently decided to rebuild my data, basically starting over from scratch with the PDF’s I got from the LANTA website. My current workflow is:

    PDF  —> CSV —> cleaned-up CSV —> GeoJSON —> cleaned-up GeoJSON —> (eventually) a PostGIS database

    The conversion from PDF to CSV was automatic, using a Java program I found online, and the CSV cleanup — fixing things like transposed latitude/longitude, missing minus signs etc — was done manually (using a text editor and LibreOffice Calc), which was relatively uneventful but  laborious — there are 68 individual bus routes, each with its own file.

    Things got even more laborious with the next two tasks. My first go-around with the conversion to GeoJSON was done manually within QGIS: load each of the CSV files, individually filling out the required parameters for each one. I wasn’t looking forward to converting the files individually, so I wrote a Python script to save all my route layers in GeoJSON format. (Just as an aside, I have to say I really like GeoJSON as a vector file format: I find it much easier to work with than the dated, unwieldy Shapefile standard; it’s also easier to open and work with in the JOSM editor. All my new data, if it’s not going into the database, is getting stored as GeoJSON files.)

    The “GeoJSON cleanup” is where I massage the data into the forms I want: some of the table columns are unnecessary, some need to be renamed, there are a few extra columns to add (and populate), and finally I wanted to convert the LANTA bus stop names format (in  Robbie-the-Robot-style ALL CAPS) to something a little easier o the eyes. Doing this manually would have been beyond laborious, so I wrote another Python script to massage the route files. This turned out to be more of a learning experience — as in, multiple versions of the program failed spectacularly until I got it right — and probably took longer than the brute force, manual changes approach would have, but at least it wasn’t laborious…

    I’m still not really sure why this version worked when others did not, but here is my code:

    # script to run through all visible layers,
    # adding/deleting/renaming fields as required
    # to convert from LANTA bus data to something
    # more like OpenStreetMap bus stop attributes
    # it also properly capitalizes feature names

    from PyQt4.QtCore import QVariant
    import re

    # some functions and regular expressions for string manipulation
    def match_lower( matchobj ):
    return matchobj.group().lower()
    def match_upper ( matchobj ):
    return matchobj.group().upper()
    reg = re.compile( 'Lati|Longi|Time|At Street|On Street|Direct|Placem' )
    reg_ns = re.compile( r'\(ns|fs|mid|off\)|\bncc\b|\bhs\b', re.IGNORECASE )
    reg_nth = re.compile( r'[1-9]?[0-9][a-z]{,2}', re.IGNORECASE )
    reg_leftParen = re.compile( r'([^\s])(\(\w*\))' )
    reg_rightParen = re.compile( r'(\))([^\s])' )
    reg_space = re.compile( r'\s+' )

    for layer in iface.mapCanvas().layers():

    # reset these variables for each new layer processed

    myLayerName = layer.name()
    highwayExists = False
    networkExists = False
    operatorExists = False
    publicExists = False
    busExists = False
    routeExists = False
    delList=[]

    layer.startEditing()
    pr = layer.dataProvider()

    # change the names of some fields
    fields = pr.fields()
    count = 0
    for field in fields:
    fieldName = field.name()
    print "test for changing field name " + fieldName + " count ", count
    if ( fieldName == 'Public Information Name' ):
    print 'changing to name'
    layer.renameAttribute( count, 'name' )
    if ( fieldName == 'Stop Number' ):
    print 'changing to ref'
    layer.renameAttribute( count, 'ref' )
    if ( fieldName == 'Stop Order' ):
    print 'changing to stop_order'
    layer.renameAttribute( count, 'stop_order' )
    count += 1
    layer.updateFields()

    layer.commitChanges()
    layer.reload()
    layer.startEditing()
    pr = layer.dataProvider()

    # delete some fields
    fields = pr.fields()
    count = 0
    for field in fields:
    fieldName = field.name()
    print "test for deleting fields " + fieldName + " count ", count
    m = reg.match( fieldName )
    if m:
    print fieldName
    delList.append( count )
    print delList
    count += 1
    pr.deleteAttributes(delList)
    layer.updateFields()

    layer.commitChanges()
    layer.reload()
    layer.startEditing()
    pr = layer.dataProvider()

    # add some fields, checking if they don't already exist
    count = 0
    fields = pr.fields()
    for field in fields:
    fieldName = field.name()
    print "test for adding fields " + fieldName + " count ", count
    if( fieldName == 'highway' ):
    highwayExists = True
    print 'highway', count
    if( fieldName == 'network' ):
    networkExists = True
    print 'network', count
    if(fieldName == 'public_transport' ):
    publicExists = True
    if(fieldName == 'bus' ):
    busExists = True
    if ( fieldName == 'operator' ):
    operatorExists = True
    if( field.name() == 'route' ):
    routeExists = True
    count += 1
    if( not highwayExists ):
    print "adding highway"
    pr.addAttributes( [ QgsField("highway", QVariant.String) ] )
    layer.updateFields()
    if( not networkExists ):
    print "adding network"
    pr.addAttributes( [ QgsField("network", QVariant.String) ] )
    if( not operatorExists ):
    print "adding operator"
    pr.addAttributes( [ QgsField("operator", QVariant.String) ] )
    if( not publicExists ):
    print "adding public_transportation"
    pr.addAttributes( [ QgsField("public_transport", QVariant.String) ] )
    if( not busExists ):
    print "adding bus"
    pr.addAttributes( [ QgsField("bus", QVariant.String) ] )
    if not routeExists:
    print "adding route"
    pr.addAttributes( [ QgsField('route', QVariant.String) ] )
    layer.updateFields()

    # add attributes to new fields for all features
    for feature in layer.getFeatures():
    feature['highway'] = "bus_stop"
    feature['network'] = 'LANTA'
    feature['operator'] = 'Lehigh and Northampton Transportation Authority'
    feature['public_transport'] = 'platform'
    feature['bus'] = 'yes'
    feature['route'] = myLayerName
    layer.updateFeature(feature)
    layer.updateFields()

    # clean up text in name field
    fieldName = 'name'
    for feature in layer.getFeatures():
    myString = feature[fieldName]
    myString = myString.title()
    myString = reg_ns.sub( match_upper, myString )
    myString = reg_nth.sub( match_lower, myString )
    myString = reg_space.sub( ' ', myString )
    myString = reg_leftParen.sub( r'\1 \2 ', myString )
    mystring = reg_rightParen.sub( r'\1 \2', myString )
    print myString
    feature[fieldName] = myString
    layer.updateFeature(feature)

    layer.commitChanges()
    layer.reload()

    Once I got this up and running, I realized that I wanted t do some more preliminary cleanup on my spreadsheets, so I was back to square one. I couldn’t really find out how to do a bulk load of my CSV files into QGIS, and I realized that QGIS was just using ogr2ogr under the hood, so I decided to do the bulk converting, CSV to GeoJSON, with a shell script that calls ogr2ogr. Yet another learning curve later, and it works great. More code:

    for i in *.csv
    do
    echo $i
    tail -n+2 $i | ogr2ogr -nln ${i%.csv} -f "GeoJSON" ${i%csv}geojson \
    CSV:/vsistdin/ -oo X_POSSIBLE_NAMES=Lon* -oo Y_POSSIBLE_NAMES=Lat* -oo KEEP_GEOM_COLUMNS=NO
    ogrinfo ${i%csv}geojson
    done

    It struck me then, that all my data was really text, and so working with it in a more unix-ey fashion, with shell scripting and text manipulation programs (sed, awk) to do the conversions directly from the CSV files, was probably my better strategy. Oh well, I did the first part of it with bash at least, and the Python script works well enough.

    UPDATE:

    I did it anyway, using awk to add/subtract/rename/Capitalize the CSV data before running it through ogr2ogr. The code (below) is about 35 lines (as opposed to 150 for the Python script, which only does part of the job anyway) and runs really fast:

    #! /bin/bash
    for i in *.csv
    do
    echo Converting $i to GeoJSON
    cat $i | awk -F "," -v rtname=${i%.csv} 'BEGIN {
    }
    $2 != "" && /Stop/ {
    print "ref,Latitude,Longitude,name,stop_order,highway,public_transport,bus,network,operator,route"
    }
    $2 != "" && /^[0-9]{4,4}/ {
    string = tolower($8)
    n=split(string,a," ")
    string=toupper(substr(a[1],1,1)) substr(a[1],2)
    for(i=2;i<=n;i++) {
    string = string " " toupper(substr(a[i],1,1)) substr(a[i],2)
    }
    t_str = "\(ns\)|\(fs\)|\(mid\)|\b[nN]cc\b|\b[Hh]s\b"
    if ( match( string, t_str, match_array ) ) {
    the_match = toupper(match_array[0])
    gsub(t_str, the_match, string)
    }
    gsub(/ *\(/, " (", string)
    $8 = string
    print $1 "," $2 "," $3 "," $8 "," $9 ",bus_stop,platform,yes,LANTA,Lehigh and Northampton Transportation Authority," rtname
    }' > test1.csv
    cat test1.csv
    ogr2ogr -nln ${i%.csv} -f "GeoJSON" ${i%csv}geojson test1.csv -oo KEEP_GEOM_COLUMNS=NO
    ogrinfo ${i%csv}geojson
    rm test1.csv
    done


  • A Wrinkle In Time

    Anne and I saw this last night. Meh — I was not impressed. I’ll grant that it was pretty close to (a simplified version of) the book, and that I am not the target audience for the movie (or the book for that matter) by about four decades, and that I did enjoy large stretches of the movie, but there were other large stretches that just left me annoyed. On the whole, the movie left me with the same, sanctimonious  “oh the wonder of it all!” vibe of a 90’s era computer advertisement, one targeting parents for their kids’ education, full of photogenic kids staring rapt at math-ey and science-ey graphics. I was seriously rolling my eyes by about 20 minutes into the movie…

    The casting was also kind of spotty, and in a weird way: the more likely I knew an actor, the worse they were here. That is, the kids were all pretty good, but Oprah was awful — more of that sanctimony, maybe.

    Anne kinda-sorta agreed with my “meh, kid stuff” assessment, but she didn’t think it was as bad as all that. She read the book as an adult though, reading it to/with Ben and Emmi and seeing it through their eyes, so she may have been more sympathetic.

    Anyway, it was a night out, and I actually would recommend it for tweens, especially fans of the book.


  • Watching The Snow Fall

    Posted on by Don

    The last storm (on Wednesday) came with a lot of hype, and I was disappointed to wake up with no snow on the ground, just rainy surfaces rather than the advertised snowpocalypse, but then snow started falling midmorning and it came down all day. It was a heavy, wet snow, but there was nowhere as much as they were calling for: we got maybe 4″ on the ground rather than the expected 12″ — the storm tracked east of us, apparently, and we missed the brunt of it, though areas west and north of us got some accumulation. Go figure.

    I got out Tuesday for a nice, pre-snowpocalypse ride on the towpath, which was in great shape — conditions had been improving, and I expected this would be the last chance this week for a decent ride. I rode down to the waterfall in Easton and back, really pleasant. After that I got my act together then went over to Southside — a little early, so I could get a few photos, for some OpenSteetMap mapping at the new parking garage — to meet Anne for dinner at La Lupita before going to see Colson Whitehead talk at Zoellner Arts Center.

    That was really good: he started with “I was born a poor black child” à la Steve Martin, did several readings from The Underground Railroad, talked about his career, his writing process, and writing as a part of his life in general. The Underground Railroad was the subject of a number of workshops at Lehigh; the event was well-attended by students as well as the usual bookish crowd, and the Q&A afterward was pretty decent.

    Wednesday was spent waiting for snow, watching snow from inside while I did computer stuff and Anne did her spinning, and then watching the storm peter out… I got in another bike ride yesterday after some trivial shoveling, just going over to the CAT office to help Scott move some shelves, the first step in his office reconfiguration project. It was a bit chilly, but the air felt fresh and very spring-like.

    Today I woke up and looked outside — snow flurries.