The Easiest Way to Save and Share Code Snippets on the web

crash.py

python

last edit: Aug, 11th 2011 | jump to bottom

__author__ = 'brycehendrix@gmail.com'
 
import urllib2, urllib
import json
import math
import os
import numpy
 
from enthought.chaco.api import Plot, ArrayPlotData, ImageData
from enthought.chaco.tools.api import PanTool, ZoomTool, LineInspector
from enthought.enable.api import ComponentEditor
from enthought.traits.api import HasTraits, Array, Int, Instance, Property, \
        cached_property, Any, Float, Tuple, on_trait_change
from enthought.traits.ui.api import View, Item, VGroup
 
class Route(HasTraits):
 
    latitudes = Array
    longitudes = Array
    positions = Property(Array, depends_on='latitudes, longitudes')
    data_bounds = Property(Tuple, depends_on='latitudes, longitudes')
    distances = Array
    speeds = Array
    altitudes = Array
    center = Array
    zoom = Int
    map_image = Property(Any, depends_on='latitudes, longitudes')
    map_padding = Float(0.2)
 
    map_plot = Instance(Plot)
    alt_plot = Instance(Plot)
    speed_plot = Instance(Plot)
 
    traits_view = View(VGroup(Item('map_plot', editor=ComponentEditor(width=640, height=480),
                                show_label=False, width=640, height=0.6),
                              Item('alt_plot', editor=ComponentEditor(width=640, height=100),
                                show_label=False, width=640, height=0.2),
                              Item('speed_plot', editor=ComponentEditor(width=640, height=100),
                                show_label=False, width=640, height=0.2)),
                       title='Route Data',
                       height=800)
 
    def __init__(self, *args, **kw):
        super(Route, self).__init__(*args, **kw)
 
        # tie the alt plot and speed plot's horizontal range so
        # panning left and right is synchronized
        self.alt_plot.index_range = self.speed_plot.index_range
 
    def _alt_plot_default(self):
        plot_data = ArrayPlotData()
        plot_data.set_data('alt', self.altitudes/1.609)
        plot_data.set_data('dist', self.distances/1.609)
        plot = Plot(plot_data)
 
        renderer = plot.plot(('dist', 'alt'), color='red')[0]
        index_inspector = LineInspector(renderer, axis='index', write_metadata=True)
        value_inspector = LineInspector(renderer, axis='value', write_metadata=True)
        renderer.tools += [index_inspector, value_inspector]
        renderer.overlays  += [index_inspector, value_inspector]
 
        plot.tools.append(ZoomTool(plot))
        plot.tools.append(PanTool(plot))
        plot.padding=[40,10,0,0]
 
        return plot
 
    def _speed_plot_default(self):
        plot_data = ArrayPlotData()
        plot_data.set_data('speed', self.speeds * (3600.0/1000)/1.609)
        plot_data.set_data('dist', self.distances/1.609)
        plot = Plot(plot_data)
 
        renderer = plot.plot(('dist', 'speed'), color='red')[0]
        index_inspector = LineInspector(renderer, axis='index', write_metadata=True)
        value_inspector = LineInspector(renderer, axis='value', write_metadata=True)
        renderer.tools += [index_inspector, value_inspector]
        renderer.overlays  += [index_inspector, value_inspector]
 
        plot.tools.append(ZoomTool(plot))
        plot.tools.append(PanTool(plot))
        plot.padding=[40,10,0,20]
 
 
        return plot
 
    def _map_plot_default(self):
 
        lat, lon = self._lat_lon_to_screen(self.latitudes, self.longitudes)
 
        plot_data = ArrayPlotData()
        plot_data.set_data('image', self.map_image)
        plot_data.set_data('lon', lon)
        plot_data.set_data('lat', lat)
        plot_data.set_data('sel_lon', numpy.array([]))
        plot_data.set_data('sel_lat', numpy.array([]))
 
        plot = Plot(plot_data, default_origin='bottom left')
        plot.img_plot('image')
        plot.plot(('lon', 'lat'), type='scatter', marker='circle', marker_size=6,
                                 color='blue', outline_color='blue')
        plot.plot(('sel_lon', 'sel_lat'), type='scatter', marker='circle', marker_size=10,
                                        color='transparent', outline_color='black')
 
        zoom = ZoomTool(component=plot)
        pan = PanTool(component=plot)
        plot.tools += [zoom, pan]
        plot.padding=[40,10,0,0]
 
        return plot
 
    @cached_property
    def _get_positions(self):
        return numpy.vstack((self.latitudes, self.longitudes)).T
 
    @cached_property
    def _get_data_bounds(self):
        min_lat = self.latitudes.min()
        max_lat = self.latitudes.max()
        min_lon = self.longitudes.min()
        max_lon = self.longitudes.max()
 
        # lower left and upper right
        return min_lat, min_lon, max_lat, max_lon
 
    @cached_property
    def _get_map_image(self):
        map_filename = os.path.join(os.path.dirname(__file__), 'osm_map.png')
        if os.path.exists(map_filename):
            img_data = ImageData.fromfile(map_filename)
            img_data._data = img_data._data[::-1]
            return img_data
 
        min_lat, min_lon, max_lat, max_lon = self.data_bounds
        padding = (max_lat-min_lat)*self.map_padding, (max_lon-min_lon)*self.map_padding
 
        min_lat -= padding[0]
        max_lat += padding[0]
        min_lon -= padding[1]
        max_lon += padding[1]
 
        link = 'http://tile.openstreetmap.org/cgi-bin/export?bbox='
        link += '%f,%f,%f,%f' % (min_lon, min_lat, max_lon, max_lat)
        link += '&scale=3500&format=png'
 
        print link
 
        urllib.urlretrieve(link, map_filename)
 
        img_data = ImageData.fromfile(map_filename)
        img_data._data = img_data._data[::-1]
        return img_data
 
    def _lat_lon_to_screen(self, lat, lon):
        height, width, depth = self.map_image._data.shape
 
        lon_scale = width/((max(self.longitudes)-min(self.longitudes))*(1+2*self.map_padding))
        lat_scale = height/((max(self.latitudes)-min(self.latitudes))*(1+2*self.map_padding))
 
        min_lat, min_lon, max_lat, max_lon = self.data_bounds
        padding = (max_lat-min_lat)*self.map_padding, (max_lon-min_lon)*self.map_padding
 
        lon = (lon - min(self.longitudes) + padding[1])*lon_scale
        lat = (lat - min(self.latitudes) + padding[0])*lat_scale
 
        return lat, lon
 
    @on_trait_change('speed_plot.datasources.metadata, alt_plot.datasources.metadata')
    def _update_scatter(self, obj, name, event):
        if 'selections' in obj.metadata:
            # set the selected map point if the object which changed is one of the
            # index ranges (not the value ranges)
            if obj in [comp.index for comp in
                       self.speed_plot.components + self.alt_plot.components]:
                d = obj.metadata['selections']
 
                # the index is sorted, so find the point before
                indices = numpy.where(obj._data < d)[0 ]
 
                if len(indices) == 0:
                    index = 0
                else:
                    index = indices[-1]
 
                if index >= (len(obj._data) - 1):
                    lat, lon = self._lat_lon_to_screen(numpy.array([self.latitudes[-1]]),
                                                       numpy.array([self.longitudes[-1]]))
                else:
                    d1 = d - obj._data[index]
                    d2 = obj._data[index + 1] - d
                    if d2 < d1:
                        index += 1
 
                    lat, lon = self._lat_lon_to_screen(numpy.array([self.latitudes[index]]),
                                                       numpy.array([self.longitudes[index]]))
 
                self.map_plot.data['sel_lat'] = lat
                self.map_plot.data['sel_lon'] = lon
 
        else:
            # clear the selected map point
            self.map_plot.data['sel_lat'] = numpy.array([])
            self.map_plot.data['sel_lon'] = numpy.array([])
 
        self.map_plot.request_redraw()
 
def get_route():
    headers = {'Accept' : 'application/json'}
    req = urllib2.Request('http://bikko.net/route/572', headers=headers)
    response = urllib2.urlopen(req)
    json_obj = json.loads(response.read())
 
    return Route(latitudes=json_obj['latitudes'], longitudes=json_obj['longitudes'],
                  distances=json_obj['distances'], speeds=json_obj['speed'],
                  altitudes=json_obj['altitudes'], center=json_obj['center'], zoom=json_obj['zoom'],
                  map_type='gmap')
 
route = get_route()
route.configure_traits()
 
83 views