“I have often felt that programming is an art form, whose real value can only be appreciated by another versed in the same arcane art;”
- Ed Nather
The Story of Mel, a Real Programmer
I started trying to lose weight a while back, since we both know I’m a bit heavy and sitting in front of a computer isn’t going to lose the weight for me.
Naturally, it’s important that I incorporate technology into my weight loss somehow, right? So I decided to give the Google Visualizations API a spin.
I worked up a quick data format and a method to pop the data out. Nothing fancy, just a fixed width flat file. This doesn’t deserve a database.
1 2 | 2010-06-30 235.4 2010-06-29 236.8 |
Easy to read, easy to edit, and easy to consume. Every morning I just hop on the server, add the day’s weight and log off.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php // Get the max days back we want to look. $max_days = 7; if( isset( $_REQUEST['days'] ) and ! empty( $_REQUEST['days'] ) ) $max_days = intval( $_REQUEST['days'] ); $i = 0; $lines = array(); $fh = fopen( 'data.txt', 'r' ); while( ! feof( $fh ) and ++$i <= $max_days ) { $line = fgets( $fh ); if( empty( $line ) ) { continue; } array_unshift( $lines, $line ); } fclose( $fh ); |
Now I just needed to represent it. The API is very object oriented and easy to work with. I wish there was a less verbose way of presenting the data, but you can’t have everything.
Actually, there may be a better way, I just didn’t come across it while speed reading the docs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | function drawChart() { var data = new google.visualization.DataTable(); data.addColumn( 'string', 'Date' ); data.addColumn( 'number', 'Weight' ); data.addRows( <?php echo count( $lines ); ?> ); <?php $i = 0; foreach( $lines as $line ): ?> data.setValue( <?php echo $i; ?>, 0, '<?php echo substr( $line, 0, 10 ); ?>' ); data.setValue( <?php echo $i; ?>, 1, <?php echo floatval( substr( $line, 11 ) ); ?> ); <?php ++$i; endforeach; ?> var chart_div = document.getElementById( 'chart_div' ); var chart = new google.visualization.LineChart( chart_div ); chart.draw( data, { width: 800, height: 600, title: 'Weight Over Time' } ); } |
And there you have it, fancy charting in no time.
See it in action at http://static.velvetcache.org/weight.php
Get the full source at http://gist.github.com/459148.
Posted July 5th, 2010 - PermalinkI’ve been meaning to check out the Tweepy for a while and got around to it today. It’s a Python library for interacting with Twitter. The feature I’m most interested in is the streaming API support, which isn’t advertised much by Tweepy but seems pretty solid.
Tweepy has pretty good documentation, and the code is terse and readable, but what I found most useful was the examples repository, which had the only example of streaming with Tweepy that I could find in the official documentation.
It’s really straightforward. Implement a tweepy.streaming.StreamListener to consume data, set up a tweepy.streaming.Stream with that listener, then pull the trigger on the streaming function you want to use.
Here’s a quick example I set up to track the filter keyword “omaha”.
# -*- coding: utf-8 -*- from tweepy.streaming import StreamListener, Stream class Listener ( StreamListener ): def on_status( self, status ): print '-' * 20 print status.text return if __name__ == "__main__": USERNAME = "YourUsernameHere" PASSWORD = "YourPasswordHere" listener = Listener() stream = Stream( USERNAME, PASSWORD, listener ); stream.filter( track=( "omaha", ) )
Update (2010-06-30)
So I got antsy about this and I upgraded to using pystache instead of my homebrew templating system. This was my first run in with mustache, and I have to say I like it, even though I used the bare minimum feature set.
New code is at http://github.com/jmhobbs/jmhobbs.github.com
Github has a cool feature called “Github Pages” that let you host static content on a subdomain of github, e.g. http://jmhobbs.github.com/.
They also provide an auto-generator for project pages that has a nice clean format which I really like. So I decided to make my user page match the look and feel of the project pages. And to boot I wanted to be able have it auto-generate since I want it to be “hands free”, otherwise I’ll forget to update it.
To make this happen I whipped up my template and then grabbed the excellent py-github from Dustin Sallings, which I have used before.
Without furthur ado I’ll just show you the source. It’s not complicated, just some API calls then search replace on a template file. If you want to use it, be sure to get the most recent version from http://github.com/jmhobbs/jmhobbs.github.com.
Throw in a cron job and you are set. Beware of lot’s of “page build” notices from Github though.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | # -*- coding: utf-8 -*- import github.github as github import yaml import time from datetime import datetime def repo_date_to_epoch ( date ): epoch = time.mktime( time.strptime( date[0:-6], "%Y-%m-%dT%H:%M:%S" ) ) return int( epoch ) def main (): print "Loading settings...." f = open( 'settings.yaml' ) settings = yaml.load( f ) f.close() gh = github.GitHub() print "Fetching user information..." user = gh.users.show( settings['username'] ) print "Fetching repository information..." repos = gh.repos.forUser( settings['username'] ) print "Sorting repositories..." repos = sorted( repos, cmp=lambda a, b: repo_date_to_epoch( b.pushed_at ) - repo_date_to_epoch( a.pushed_at ) ) print "Loading template..." f = open( 'index.html.tpl' ) template = f.read() f.close() print "Mangling template..." template = template.replace( '<% username %>', settings['username'] ) template = template.replace( '<% fullname %>', user.name ) template = template.replace( '<% email %>', user.email ) template = template.replace( '<% following %>', str( user.following_count ) ) template = template.replace( '<% followers %>', str( user.followers_count ) ) template = template.replace( '<% publicrepos %>', str( user.public_repo_count ) ) repo_string = '' for repo in repos: if repo.private: continue repo_string = repo_string + '<div class="repo"><h3><a href="' + repo.url + '">' + repo.name + '</a>' try: repo_string = repo_string + ' - <span class="small"><a href="' + repo.homepage + '">' + repo.homepage + '</a></span>' except AttributeError: pass repo_string = repo_string + '</h3>' repo_string = repo_string + "Forks: " + str( repo.forks ) + " - Watchers: " + str( repo.watchers ) + ' | ' if repo.has_issues: repo_string = repo_string + ' <a href="' + repo.url + '/issues">Issues</a> |' if repo.has_wiki: repo_string = repo_string + ' <a href="http://wiki.github.com/' + settings['username'] + '/' + repo.name + '">Wiki</a> |' if repo.has_downloads: repo_string = repo_string + ' <a href="' + repo.url + '/downloads">Downloads</a> |' repo_string = repo_string + '<br/>Last Push: ' + datetime.fromtimestamp( repo_date_to_epoch( repo.pushed_at ) ).ctime() try: repo_string = repo_string + '<pre>' + repo.description + '< /pre>' except AttributeError: repo_string = repo_string + '<br/><br/>' pass repo_string = repo_string + "</div><!--// .repo //-->\n" template = template.replace( '<% repos %>', repo_string ) ga = """ <script type="text/javascript"> var _gaq = _gaq || []; _gaq.push(['_setAccount', '<% ga_code %>']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script> """ if False != settings['google_analytics']: template = template.replace( '<% google_analytics %>', ga ) template = template.replace( '<% ga_code %>', settings['google_analytics'] ) else: template = template.replace( '<% google_analytics %>', '' ) print "Writing file..." f = open( 'index.html', 'w' ) f.write( template ) f.close() print "Done!" if __name__ == "__main__": main() |
Wow. You actually scrolled through all of that. Amazing.
Posted June 29th, 2010 - Permalink
“Computer Science is a terrible name for this business. First of all it’s not a science. It might be engineering or it might be art.”
- Harold Ableson
EE & CS Professor at MIT
Overview and Introduction to Lisp