Tuesday, February 21, 2017

Voting Districts Day 7: Post a VERY basic map

So, I'm starting to figure out how to create a map with a leaflet package in javascript.


Leafletjs' tutorial has been very helpful so far in figuring out how to make a map appear and adding a layer to it. I can then add a layer to the map by pasting the coordinates via a json file. I was able to find a shape representing NC on Github from a gentleman named Johan.

I couldn't get it to work without just cutting and pasting the JSON text into the javascript portion of the file, but I'll work on that later. However, I was able to get a shape of NC to appear down below.



You need to reference the leaflet js in the head of the html.

Note: I stuck some hyphens at the beginning of the tag so it would show on the page below.
<--link href="docs/images/favicon.ico" rel="shortcut icon" type="image/x-icon">
<--link href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" rel="stylesheet">
<--script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"><--/script>

You can then add the map and then the layer once you create it as a variable.

<--div id="mapid" style="height: 400px; width: 800px;">
<--/div>
<--script>
***Create Map***
var mymap = L.map('mapid').setView([35.505, -80.09], 7);
***Create layer variable***
var nc = ***JSON goes here***
***Add layer to map***
L.geoJSON(nc).addTo(mymap);
<--/script>

NOTE: To get the map to appear in Blogger, you have to use the HTML button, which is next to the compose button. I couldn't figure out to have my cake and eat it too. So, I typed up EVERYTHING manually, including the breaks and such, in html. Thank heavens for the preview button!

And that was the simplest way I could find to do this. This javascript is very new and foreign to me.

Next up, we are going to figure out how to create a json with our voting data (back to Python!) and shapefiles and how to read that in javascript as an external file.

Monday, February 6, 2017

Voting Districts Day 6: Voting District Draft

Next up, we are going to go through our starting points where each will take turns choosing a voting district that is closest to them. This draft of sorts is intended to cluster the voting districts together to build our congressional districts.

To do this, we are going to continually pick the closest voting district for each point until there are no more voting districts left to pick. As voting districts are picked, we will associate the voting district to the point by appending the point and its distance to the voting district to our big list consisting of each voting district and their center points (the value we used to measure the distance to the starting point). We'll also take the voting district away as an option by replacing the distance value in the matrix from the measure to 'xxxxx.' We'll know when we are done when all the values in one of the matrix rows consists of all 'xxxxx' values.

Here's the code I wrote with the usual verbose comments:

#Our list to iterate through the points, giving each a turn to get its closest voting district.
point_list = list()

#Next, until all the voting districts are picked, round robin through the points, designating the closest available voting
#district and removing that voting district as an option for the next pick.  For the ones already found, mark out with xxxxx, which will also eliminate it from being
#found as the minimum for the next point check.  Do this until all the voting districts equal xxxxx, which means they've all been designated to a point.  

#we need a variable that'll be used to hold how many voting districts haven't been chosen.  
choices_left = 1

#while there are still voting districts unspoken for...
while (choices_left > 0):
    #I want to pull an item from a list of the points using pop, but make the pop or the list random...
    #can do this with random.shuffle, then pop the last one out!
    
    #when the list is empty, fill it back up with the number of points and shuffle that list.
    if (len(point_list) == 0):
        for e in range(0,len(start_points)): point_list.append(e)
        random.shuffle(point_list)
    point_choice = point_list.pop() #pull a point.
    min_distance = min(matrix[point_choice]) #get the least distance found between a voting district and that point.
    dist_loc = matrix[point_choice].index(min_distance) #figure out which voting district has that minimum distance.
    coords[dist_loc].append([point_choice, min_distance]) #and apply the point and distance to that district as the points choice.
    #then mark that voting district as chosen by changing the distance values corresponding to that district to xxxxx.
    for f in range(0, len(matrix)):
        matrix[f][dist_loc] = 'xxxxx'

    #figure out how many voting districts have yet to be spoken for by counting how many in one line of the matrix do not equal xxxxx.   
    choices_left = len([g for g in matrix[0] if g != 'xxxxx'])
    #print(str(point_choice) + ' ' + str(min_distance) + '  ' + str(dist_loc) + '  ' + str(choices_left))

Next, we've got to figure out what to do with this data. It would be great to build a map with it to see what it looks like, but I'm not sure exactly how to pull that off.

It looks like javascript and leaflet.js may be a nice option, but there's definitely a learning curve there for me. I'll research and see what I can do.

Thursday, February 2, 2017

Voting Districts Day 5: The district/distance matrix

Next, I'm going to build a matrix showing the distance between each voting district and the start points.  

To figure out the distance between the two points, I'm going to attempt to use the pythagorean theorem (a² + b² = c²) where a equals the difference between the x coordinates and b equals the difference between the y coordinates.  This'll be a measurement "as the crow flies." 

Our point shared by the x and y axis will have the same latitude as one point and the same longitude as the other point to make a right triangle.  To calculate the distance for the x and y lines, we'll subtract the latitudes and longitudes of the points between the centroid and the starting point.  

(voting_district_x - starting_point_x)² + (voting_district_y - starting_point_y)² = (the_distance between the points)²

OR

math.sqrt(((start_points[a][0] - coords[b][2]) ** 2) + ((start_points[a][1] - coords[b][5]) ** 2))

Now I just have to do a double loop to build the matrix showing the distance between each voting district and starting point like so:

matrix = list()

for a in range(0, len(start_points)):
    point_line = list()
    for b in range(0, len(coords)):
        point_line.append(math.sqrt(((start_points[a][0] - coords[b][2]) ** 2) + ((start_points[a][1] - coords[b][5]) ** 2)))
    matrix.append(point_line)

And that should give me a nice matrix that I can run a draft through to assign voting districts to starting points!  That's what we're going to work on next.  

Wednesday, February 1, 2017

Voting Districts Day 4: Starting with Random Points

Now that we've got the center points for our voting district shapes, we need to figure out how to create central points where we can start our clustering.  

There is a random library included with Python that I hope can do the job.  It has a uniform function that will give me a random float between two numbers that I designate.  I'll just loop through to generate these random coordinates based on how many clusters I want to build.

First, I want to make sure these starting coordinates fall somewhere approximately within the state of NC.  So, I'm going to get the total min and max x and y axis values by writing ALL of the x and y points to two lists and pull a min and max from those lists to create a range for the random numbers.

import random
...
xmids = list()
ymids = list()

for x in range(0,len(shapes)):

    for y in range(0,len(shapes[x].points)):

        xmids.append(shapes[x].points[y][0]) 
        ymids.append(shapes[x].points[y][1])


start_points = list()
xmax_o = max(xmids)
xmin_o = min(xmids)
ymax_o = max(ymids)
ymin_o = min(ymids)

From there, we'll use the random.uniform method through a loop to create whatever number of points we want to start with.
start_point_count = 12 for z in range(0,start_point_count):
 start_points.append([random.uniform(xmin_o,xmax_o),random.uniform(ymin_o, ymax_o)])

And we now have our random starting points!

Next up, we are going to build ourselves a matrix consisting of the distances between the centroids of our voting district shapes and our starting points.  From there, we will then figure out which voting district should be associated with each point by going through the voting districts draft style where each point will take a turn picking its closest voting district.