ArtsAutosBooksBusinessEducationEntertainmentFamilyFashionFoodGamesGenderHealthHolidaysHomeHubPagesPersonal FinancePetsPoliticsReligionSportsTechnologyTravel

charting personal geographies - AJAX and the graphing calculator - part 3 in a series

Updated on July 5, 2011

My personal geography for the last couple weeks

I plotted the places I visited, roughly, to scale, then merged in similar plots for the other members of my household..
I plotted the places I visited, roughly, to scale, then merged in similar plots for the other members of my household..

The event handler for fetching data from the Web server

var xpts = new Array();
var ypts = new Array();
var yi = 0;
var xi = 0;

function getPath( url, coord ){

	if( url == "" ) {
		url = "/" + $( "#datafile" ).val() + ".xml";
	}
	$.get( url,
		"",
		function ( data ) {
			$( data ).find( "point" ).each( function () {
				$(this).find( "x" ).each( function () {
					xpts[xi++] = $( this ).text();
				});
				$(this).find( "y" ).each( function () {
					ypts[yi++] = $( this ).text();
				});
			});
			jgplot( coord, xpts, ypts );
	});
}

The HTML code to allow the user to call the event handler

<tr><td><img id="start_plot" src="jgplot.jpg" 
onClick="javascript:getPath('', unitsquare);"
 /></td><td><input id="datafile" name="datafile" value="path1" ></td></tr>

Fetching named data sets

In my previous Hub in this series, I covered the mechanics of obtaining input in Javascript: data format, making an HTTP request back to the server the page came from, and updating the DOM of the page that the user is viewing. In this Hub, I will let the user name the data set that they want to retrieve.

The code changes to fetch a named set of data from my Web server are not much. I just add an input tag for the user to enter the name of the data set into, and a few lines of code in jgGetPath to use the user supplied name. The javascript and HTML for doing this are on the left of the page.

The more difficult thing is to motivate what these data sets might be. For that, I will draw on a concept that I encountered in a college geography class; personal geographies. The path a person takes in their daily activities determines a lot about who they will meet and their impressions of the world around them. For example, most of our activities occur in built up areas. So, our impression of the world is that it is more made of man made things than it actually is.

Anyway, back to the problem at hand, I want to chart the locations various people visit during the course of a couple weeks. I will name the person, and the Web server will fetch the data describing where they have been, and my javascript code will chart that data. Furthermore, I want to merge the charts of different people in order to see how their daily routines relate.

For this example, I will just create a daily journal for each person under study and enter their data into a file manually. The name of the data set will just be the file name, minus path and extension. It would be a more interesting application, if the data came from cell phone records and the input name caused a server side script to extract and convert the cell phone records for the person named, but the phone company hasn't made their data available to me.

In order to merge personal geography plots for myself and others, I need to accumulate all of the data points into a single set of arrays. This is why xpts, ypts, xi and yi are global variables. I enter one plot, then add another to it. At that point, getPath, erases any plot that is already rendered by calling the jQuery functions $( ".newrectangle" ).remove and $( ".blackrectangle" ).remove() . The user can reset the accumulated plot by reloading the page.

I can imagine many ways to embellish this application. I could overlay the plot on a map, or color the lines for different people differently, for example. However, I will keep it simple. There are a couple of bugs I had to fix in my previous code, or features I had to add, depending on your point of view, in order to accommodate this new application.

I also had to generalize the scaleToCurve method of jgCoordinates to scale the x-axis, as well as, the y-axis, because when plotting a path, both the x and y values can change arbitrarily at any point. This is different from plotting functions where x moves smoothly between a start point and a finish point.

Finally, I had to force makeplotfn to return integers rather than whatever data the arrays xpts and ypts happened to contain. Otherwise, scaleToCurve would compare the returned values as strings, with unpredictable results.

So far, my data all resides in hand edited files that are stored on my Web server. In future Hubs, I will explore mechanisms for automating the generation of data for Ajax to fetch. The small, but important advance in this Hub is to allow the user to enter a string that describes the data they want to process. The data set and the plotting application are no longer hard coded together.

generalizing the scaleToCurve function

	scaleToCurve: function ( curvefn, fnstart, fnstop, delta ) {
		var pt;
		var fofpt;

		if( this.dontscale ) {
			return;
		}
		// get maximum and minimum x and y values
		fofpt = curvefn( fnstart );
		var minx = fofpt.x;
		var miny = fofpt.y;
		var maxx = fofpt.x;
		var maxy = fofpt.y;
		for( pt = fnstart + delta ; pt < fnstop; pt += delta ) {
			fofpt = curvefn( pt );
			if( fofpt.y > maxy ) {
				maxy = fofpt.y;
			}
			if( fofpt.y < miny ) {
				miny = fofpt.y;
			}
			if( fofpt.x > maxx ) {
				maxx = fofpt.x;
			}
			if( fofpt.x < minx ) {
				minx = fofpt.x;
			}
		}
		var aspectratio = ( this.y1 - this.y0 ) / ( this.x1 - this.x0 );
		if( this.y0 < miny ) {
			miny = this.y0;
		}
		if( this.y1 > maxy ) {
			maxy = this.y1;
		}
		if( this.x0 < minx ) {
			minx = this.x0;
		}
		if( this.x1 > maxx ) {
			maxx = this.x1;
		}
		var newaspectratio = ( maxy - miny ) / (maxx - minx );
		if( newaspectratio > aspectratio ) {
			// match y values and scale x values
			this.y0 = miny;
			this.y1 = maxy;
			var xlength = 1 / aspectratio * ( maxy - miny );
			this.x0 = minx + (maxx - minx) / 2 - xlength / 2;
			this.x1 = minx + (maxx - minx) / 2 + xlength / 2;
		} else {
			// match x values and scale y values
			this.x0 = minx;
			this.x1 = maxx;
			var ylength = aspectratio * ( maxx - minx );
			this.y0 = miny + (maxy - miny) / 2 - ylength / 2;
			this.y1 = miny + (maxy - miny) / 2 + ylength / 2;
		}
		if ( this.x0 < 0 && this.x1 > 0 ) {
			var yaxis1 = this.pointToScreenCoordinates( 0, this.y1 );
			var yaxis0 = this.pointToScreenCoordinates( 0, this.y0 );
			drawline( 1, yaxis0.x, yaxis0.y, yaxis1.x, yaxis1.y );
		}
		if( this.y0 < 0 && this.y1 > 0 ) {
			var xaxis1 = this.pointToScreenCoordinates( this.x1, 0 );
			var xaxis0 = this.pointToScreenCoordinates( this.x0, 0 );
			drawline( 1, xaxis0.x, xaxis0.y, xaxis1.x, xaxis1.y );
		}

	}

fixing a bug in makePlotFn

function makeplotfn( pts ) {
	var rfn = function( x ) {
		var ix = Math.round( x );
		if( ix < 0 ) {
			return( parseInt( pts[0] ) );
		}
		if( ix >= pts.length ) {
			return( parseInt( pts[ pts.length - 1 ] ) );
		}
		return( parseInt( pts[ix] ) );
	}
	return rfn;
}

The data files to describe personal geographies

pgeo.xml:
<?xml version="1.0" encoding="utf-8"?>
<path>
<point>
<x>0</x>
<y>0</y>
</point>
<point>
<x>-15</x>
<y>-10</y>
</point>
<point>
<x>0</x>
<y>0</y>
</point>
</path>
kgeo.xml :
<?xml version="1.0" encoding="utf-8"?>
<path>
<point>
<x>0</x>
<y>0</y>
</point>
<point>
<x>-7</x>
<y>40</y>
</point>
<point>
<x>0</x>
<y>0</y>
</point>
</path>
mgeo.xml:
working

This website uses cookies

As a user in the EEA, your approval is needed on a few things. To provide a better website experience, hubpages.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://corp.maven.io/privacy-policy

Show Details
Necessary
HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
LoginThis is necessary to sign in to the HubPages Service.
Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
AkismetThis is used to detect comment spam. (Privacy Policy)
HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
Features
Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
MavenThis supports the Maven widget and search functionality. (Privacy Policy)
Marketing
Google AdSenseThis is an ad network. (Privacy Policy)
Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
Index ExchangeThis is an ad network. (Privacy Policy)
SovrnThis is an ad network. (Privacy Policy)
Facebook AdsThis is an ad network. (Privacy Policy)
Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
AppNexusThis is an ad network. (Privacy Policy)
OpenxThis is an ad network. (Privacy Policy)
Rubicon ProjectThis is an ad network. (Privacy Policy)
TripleLiftThis is an ad network. (Privacy Policy)
Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
Statistics
Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)
ClickscoThis is a data management platform studying reader behavior (Privacy Policy)