A while ago, I attended a couple of RailsBridge events as a student, and I intended to come back as a volunteer. Finally, this has happened, and it was a great experience.
The event was hosted at ThoughtWorks. As it was my first TA-ing experience at such events, I asked to place me into a beginner's group. It is interesting how things change when you have to explain something to a different person - even if you know the subject matter, it takes different skills to articulate the information. I hope I will master these skills as well.
Next week, I am coming back again to teach Rails.
Monday, January 19, 2015
Tuesday, January 13, 2015
A little git trick
A little git trick I learned recently. For the safety mapping app, I am using a personal api token, which I would not want to show in Github. It turns out, it is possible to commit an entire file excluding the line you don't want to show (i.e., the api_token).
Actual details are available here.
git add -i is a command that brings up an interactive window. From there, you want to choose #5 (patch), and git will walk you through the steps. When you are ready to stage, you are presented with several choices - 'y' for yes etc. One of the useful choices is 's' - split. For example, you might have 5 new lines, and only 4 of those you want to commit. Using -s command, one can split these lines into separate commits, and proceed as needed.Actual details are available here.
Thursday, January 8, 2015
More on SafetyApp
An update on my visualization app regarding safety walking in San Francisco. The idea was to display crime only along the chosen route. The app uses Google API to return and visualize directions from point A to point B. Along this route, crime points are supposed to be displayed.
If I was doing it using traditional GIS software, I would create a buffer along the route, and clip the crime points to the buffer. I used the same logic here, but using different tools.
Google Directions API returns a number of vertices along the route, and these vertices could be used to construct a bounding box. While it is possible to construct a bounding box using the beginning and the end points in the routes, the bounding box could be too big, especially if the coordinates were too much off on either the x or y axis. For this reason, it is much better to use a buffer, which would be following the shape of the route.
At first, I constructed a bounding box around each of the vertices returned from the Directions API and I ended up with a lot of boxes. Unfortunately, datasf.org apparently has some limits on how many bounding boxes can be passed into the api call (it appears to be 46 boxes before the api call returns an error).
The next idea was to use a smoothing algorithm, which would straighten up the route a little bit and return a smaller number of vertices. The Ramer–Douglas–Peucker algorithm can be used to reduce the number of points in a curve, and I found a Javascript implementation of it here. Unfortunately, this was not particularly useful. If the curve is straightened out too much, the vertices are too spread out from each other, and the bounding boxes will have gaps in between. Technically, there is a way to construct bounding boxes in such a way that they will touch each other. However, I must admit I am not that knowledgeable about geographic algorithms - while I made some attempts in this direction, I could not quickly find a way to account for directional changes in latitude and longitude. I have some ideas on how to proceed but I will leave them for a later exploration.
In the meanwhile, I have come across a great JS library, called Turf.js. It performs all the necessary GIS processing tasks using GeoJSON data. Using Turf.js, I have come up with the following algorithm of actions: 1) get routing vertices from Google Directions; 2) create a buffer along the route; 3) use the buffer to create a bounding box and pass the bounding box coordinates into the api call, which returns crimes within the box; 4) use the buffer to clip the points to the new area; 5) happy display the points.
Below is the function that performs some of these tasks:
If I was doing it using traditional GIS software, I would create a buffer along the route, and clip the crime points to the buffer. I used the same logic here, but using different tools.
Google Directions API returns a number of vertices along the route, and these vertices could be used to construct a bounding box. While it is possible to construct a bounding box using the beginning and the end points in the routes, the bounding box could be too big, especially if the coordinates were too much off on either the x or y axis. For this reason, it is much better to use a buffer, which would be following the shape of the route.
At first, I constructed a bounding box around each of the vertices returned from the Directions API and I ended up with a lot of boxes. Unfortunately, datasf.org apparently has some limits on how many bounding boxes can be passed into the api call (it appears to be 46 boxes before the api call returns an error).
The next idea was to use a smoothing algorithm, which would straighten up the route a little bit and return a smaller number of vertices. The Ramer–Douglas–Peucker algorithm can be used to reduce the number of points in a curve, and I found a Javascript implementation of it here. Unfortunately, this was not particularly useful. If the curve is straightened out too much, the vertices are too spread out from each other, and the bounding boxes will have gaps in between. Technically, there is a way to construct bounding boxes in such a way that they will touch each other. However, I must admit I am not that knowledgeable about geographic algorithms - while I made some attempts in this direction, I could not quickly find a way to account for directional changes in latitude and longitude. I have some ideas on how to proceed but I will leave them for a later exploration.
In the meanwhile, I have come across a great JS library, called Turf.js. It performs all the necessary GIS processing tasks using GeoJSON data. Using Turf.js, I have come up with the following algorithm of actions: 1) get routing vertices from Google Directions; 2) create a buffer along the route; 3) use the buffer to create a bounding box and pass the bounding box coordinates into the api call, which returns crimes within the box; 4) use the buffer to clip the points to the new area; 5) happy display the points.
Below is the function that performs some of these tasks:
/* Calculates a route between two points
and uses coordinates along the route to create a bounding box and a buffer
around the route. Constructs a callback function into which the coordinates,
crime types, and dates are passed.
*/
function calcRoute(callback) {
var request = {
origin: from,
destination: to,
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(request, function(response, status)
{
if (status == google.maps.DirectionsStatus.OK) {
var routes = response.routes[0];
var google_coords = [];
for (var i = 0; i < routes.overview_path.length; i++){
var coordinates = routes.overview_path[i];
/*
A reminder to myself what longitude and latitude is.
coordinates.D; // x, longitude
coordinates.k; // y, latitude
*/
google_coords.push([coordinates.D, coordinates.k]);
}
// create a feature collection of line strings for turf library
var feature_collection = turf.linestring(google_coords);
// create a buffer using turf library
var buffer = turf.buffer(feature_collection, 0.25, 'kilometers');
// create a bounding envelope of the buffer using turf library
var envelope = turf.envelope(buffer);
/* get upper left and lower right corners of the bounding box and
concatenete them together to be in the following form:
maxLat, minLong, minLat, maxLong; e.g., 41.885001, -87.645939, 41.867011, -87.618516
*/
var first_corner = envelope.geometry.coordinates[0][3].sort(function(a,b){
return b - a;
});
var second_corner = envelope.geometry.coordinates[0][1].sort(function(a,b){
return b - a;
});
var flattened = [first_corner, second_corner].reduce(function(a,b){
return a.concat(b);
});
/*
use coordinates of the bounding box to costruct query along with data on
crime types from checkboxes and dates from slider to be passed into
the callback function
*/
var query = "within_box(location, " + flattened[0] + ", " +
flattened[1] + ", " + flattened[2] + ", " + flattened[3] + ")";
if (crimeTypeFromCheckbox != ''){
var apiCall = baseUrl + "&$where=" + query + " AND" + crimeTypeFromCheckbox + dateFromSlider;
}else{
var apiCall = '';
}
var arr = [];
arr.push(apiCall);
arr.push(buffer);
callback(arr);
directionsDisplay.setDirections(response);
}
});
}
Sunday, January 4, 2015
Mapping crime
As I am working on improving my Javascript skills, I've decided to built an app that I've conceived some time ago. As I go to meetups, I frequently choose to walk (feels good to exercise!); however, I don't always know the safety level of neighborhoods in San Francisco. I always wanted to know the state of crime along my chosen route.
So finally, I've started working on this idea. At the moment, it is still a prototype but most of the basic functionality is in and working. I am attaching a picture here for now, but I will be posting more details about the app as I am finishing it up.
So finally, I've started working on this idea. At the moment, it is still a prototype but most of the basic functionality is in and working. I am attaching a picture here for now, but I will be posting more details about the app as I am finishing it up.
Subscribe to:
Comments
(
Atom
)
