XClose

An introduction to research programming with Python

Home
Menu

Understanding the "Greengraph" Example

We now know enough to understand everything we did in the initial example chapter on the "Greengraph". Go back to that part of the notes, and re-read the code.

Now, we can even write it up into a class, and save it as a module.

Classes for Greengraph

In [1]:
%%bash
mkdir -p greengraph # Create the folder for the module (on mac or linux)
In [2]:
%%writefile greengraph/graph.py
import numpy as np
import geopy
from .map import Map

class Greengraph(object):
    def __init__(self, start, end):
        self.start=start
        self.end=end
        self.geocoder=geopy.geocoders.GoogleV3(domain="maps.google.co.uk")
        
    def geolocate(self, place):
        return self.geocoder.geocode(place, exactly_one=False)[0][1]
    
    def location_sequence(self, start,end,steps):
      lats = np.linspace(start[0], end[0], steps)
      longs = np.linspace(start[1],end[1], steps)
      return np.vstack([lats, longs]).transpose()

    def green_between(self, steps):
        return [Map(*location).count_green()
                for location in self.location_sequence(
                    self.geolocate(self.start), 
                    self.geolocate(self.end),
                    steps)]
Writing greengraph/graph.py
In [3]:
%%writefile greengraph/map.py

import numpy as np
from io import BytesIO
from matplotlib import image as img
import requests

class Map(object):
    def __init__(self, lat, long, satellite=True, zoom=10, size=(400,400), sensor=False):
        base="http://maps.googleapis.com/maps/api/staticmap?"
  
        params = dict(
            sensor= str(sensor).lower(),
            zoom= zoom,
            size= "x".join(map(str, size)),
            center= ",".join(map(str, (lat, long) )),
            style="feature:all|element:labels|visibility:off"
        )
    
        if satellite:
            params["maptype"]="satellite"
        
        self.image = requests.get(base, params=params).content # Fetch our PNG image data
        self.pixels = img.imread(BytesIO(self.image))
        
    def green(self, threshold):
        # Use NumPy to build an element-by-element logical array
        greener_than_red = self.pixels[:,:,1] > threshold* self.pixels[:,:,0]
        greener_than_blue = self.pixels[:,:,1] > threshold*self.pixels[:,:,2]
        green = np.logical_and(greener_than_red, greener_than_blue) 
        return green
    
    def count_green(self, threshold = 1.1):
        return np.sum(self.green(threshold))
    
    def show_green(data, threshold = 1.1):
        green = self.green(threshold)
        out = green[:,:,np.newaxis]*array([0,1,0])[np.newaxis,np.newaxis,:]
        buffer = BytesIO()
        result = img.imsave(buffer, out, format='png')
        return buffer.getvalue()
Writing greengraph/map.py
In [4]:
%%writefile greengraph/__init__.py
from .graph import Greengraph
Writing greengraph/__init__.py

Invoking our code and making a plot

In [5]:
%matplotlib inline
from matplotlib import pyplot as plt
from greengraph import Greengraph


mygraph = Greengraph('New York','Chicago')
data = mygraph.green_between(20)
---------------------------------------------------------------------------
ConfigurationError                        Traceback (most recent call last)
Cell In [5], line 6
      2 from matplotlib import pyplot as plt
      3 from greengraph import Greengraph
----> 6 mygraph = Greengraph('New York','Chicago')
      7 data = mygraph.green_between(20)

File ~/work/doctoral-programming-intro/doctoral-programming-intro/02-novice/greengraph/graph.py:9, in Greengraph.__init__(self, start, end)
      7 self.start=start
      8 self.end=end
----> 9 self.geocoder=geopy.geocoders.GoogleV3(domain="maps.google.co.uk")

File /opt/hostedtoolcache/Python/3.8.14/x64/lib/python3.8/site-packages/geopy/geocoders/google.py:113, in GoogleV3.__init__(self, api_key, domain, scheme, client_id, secret_key, timeout, proxies, user_agent, ssl_context, adapter_factory, channel)
    110 self.secret_key = secret_key
    112 if not self.premier and not api_key:
--> 113     raise ConfigurationError(
    114         'Since July 2018 Google requires each request to have an API key. '
    115         'Pass a valid `api_key` to GoogleV3 geocoder to fix this error. '
    116         'See https://developers.google.com/maps/documentation/geocoding/usage-and-billing'  # noqa
    117     )
    119 self.api_key = api_key
    120 self.domain = domain.strip('/')

ConfigurationError: Since July 2018 Google requires each request to have an API key. Pass a valid `api_key` to GoogleV3 geocoder to fix this error. See https://developers.google.com/maps/documentation/geocoding/usage-and-billing
In [6]:
plt.plot(data)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [6], line 1
----> 1 plt.plot(data)

NameError: name 'data' is not defined