{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Notebook-8: Dictionaries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lesson Content \n", "\n", "In this lesson, we'll continue our exploration of more advanced data structures. Last time we took a peek at a way to represent ordered collections of items via **lists**.\n", "\n", "This time we'll use **dictionaries** to create collections of unordered items (this is just an easy distinction - there's much more to it - but it's a good way to start wrapping your head around the subject).\n", "\n", "### In this Notebook\n", "\n", "- Creating dictionaries\n", "- Accessing elements of dictionaries\n", "- Methods of dictionaries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Dictionaries\n", "----\n", "\n", "Dictionaries are another data type in Python that, like lists, contains multiple items. The difference is that while lists use an index to access _ordered_ items, dictionaries use 'keys' to access _unordered_ values.\n", "\n", "You can go back to our short video that talks about dictionaries:\n", "\n", "[![The Basics](http://img.youtube.com/vi/UDNtW3sy-og/0.jpg)](https://youtu.be/UDNtW3sy-og?t=613)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like lists, dictionaries are also found in other programming languages, often under a different name. For instance, Python dictionaries might be referred to elsewhere as \"maps\", \"hashes\", or \"associative arrays\").\n", "\n", "According to the [Official Docs](https://docs.python.org/2/tutorial/datastructures.html#dictionaries):\n", "\n", "> It is best to think of a dictionary as an unordered set of key-value pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: {}\n", "\n", "In other words, dictionaries are not lists: instead of just a checklist, we now have a _key_ and a _value_. We use the key to find the value. So a generic dictionary looks like this:\n", "\n", "```python\n", "theDictionary = {\n", " key1: value1,\n", " key2: value2,\n", " key3: value3,\n", " ...\n", "}\n", "```\n", "Each key/value _pair_ is linked by a ':', and each pair is separated by a ','. It doesn't really matter if you put everything on newlines (as we do here) or all on the same line. We're just doing it this way to make it easier to read.\n", "\n", "Here's a more useful implementation of a dictionary:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "myDict = {\n", " \"key1\": \"Value 1\",\n", " 3: \"3rd Value\",\n", " \"key2\": \"2nd Value\",\n", " \"Fourth Key\": [4.0, 'Jon']\n", "}\n", "print(myDict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At the danger of repeating ourselves (but to make the point!): an important difference between `dictionaries` and `lists` is that dictionaries are unordered. Always remember that you have no idea where things are stored in a `dictionary` and you can't rely on indexing like you can with a `list`. From this perspective, a Python dictionary is _not_ like a real dictionary (as a real dictionary presents the keys, i.e. words, in alphabetical order). \n", "\n", "And notice too that every type of data can go into a dictionary: strings, integers, and floats. There's even a `list` in this dictionary (`[4.0, 'Jon']`)! The _only_ constraint is that the **key must be *immutable***; this means that it is a simple, static identifier and that can't change." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this will result in an error\n", "myFaultyDict = {\n", " [\"key1\", 1]: \"Value 1\", \n", " \"key2\": \"2nd Value\", \n", " 3: \"3rd Value\", \n", " 8.0: [5, 'jon']\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This doesn't work because you can't use a list (`[\"key1\",1]`) as a key, though as you saw above you can use a list as a _value_. For more on the subject of (im)mutability checkout [this SO answer](http://stackoverflow.com/a/8059504) ).\n", "\n", "## Accessing Dictionaries\n", "\n", "Like lists, we access an element in a dictionary using a 'location' marked out by a pair of square brackets (*[...]*). The difference is that the index is no longer an integer indicating the position of the item that we want to access, but is a *key* in the *key:value* pair:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(myDict[\"key1\"])\n", "print(myDict[\"Fourth Key\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice how now we just jump straight to the item we want? We don't need to think about \"Was that the fourth item on the list? Or the fifth?\" We just use a sensible key, and we can ask for the associated value directly.\n", "\n", "#### A challenge for you!\n", "\n", "How would you print out \"2nd Value\" from `myDict`?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(???)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(myDict[\"key2\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When it comes to error messages, `dict`s and `list`s behave in similar ways. If you try to access a dictionary using a key that doesn't exist then Python raises an *exception*. \n", "\n", "What is the name of the exception generated by the following piece of code? Can you find it the [Official Docs](https://docs.python.org/2/library/exceptions.html)?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(myDict[99])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Handy, no? Again, Python's error messages are giving you helpful clues about where the problem it's encountering might be! Up above we had a `TypeError` when we tried to create a key using a list. Here, we have a `KeyError` that tells us something must be wrong with using `99` as a key in `myDict`. In this case, it's that there is no key 99!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### A challenge for you\n", "\n", "Can you turn these lists into dictionary called `capitalDict`?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "country = ['Costa Rica','Croatia','Cuba'] #keys\n", "capital_city = ['San Jose','Zagreb','Havana'] #values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We already found out that we can easily convert between different types. Dictionary is also a data type, so we can convert these lists to dictionary just like we convert strings into integers using `str` and `int`. However, since we need to pair them, we need an additional function called `zip` to pair the keys and values." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "capitalDict = ???(zip(???,???))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "capitalDict = dict(zip(country,capital_city))\n", "capitalDict" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How would you print out the capital city of Croatia from `capitalDict`?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(???)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(capitalDict['Croatia'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating a Simple Phone Book\n", "\n", "One of the simplest uses of a dictionary is as a phone book! (If you're not sure what a phone book is [here's a handy guide](https://www.youtube.com/watch?v=QtntnfgIyUg) and [here's an example of someone using one](https://www.youtube.com/watch?v=updE5LVe6tg)). \n", "\n", "So here are some useful contact numbers:\n", "1. American Emergency Number: 911\n", "2. British Emergency Number: 999\n", "3. Icelandic Emergency Number: 112\n", "4. French Emergency Number: 112\n", "5. Russian Emergency Number: 102\n", "\n", "Now, how would you create a dictionary that allowed us to look up and print out an emergency phone number based on the [two-character ISO country code](http://www.nationsonline.org/oneworld/country_code_list.htm)? It's going to look a little like this:\n", "```python\n", "eNumbers = {\n", " ...\n", "}\n", "print(\"The Icelandic emergency number is \" + eNumbers['IS'])\n", "print(\"The American emergency number is \" + eNumbers['US'])\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eNumbers = {\n", " \"IS\": '112', # It's not very important here whether we use single- or double-quotes\n", " \"US\": '911'\n", "}\n", "print(\"The Icelandic emergency number is \" + eNumbers['IS'])\n", "print(\"The American emergency number is \" + eNumbers['US']) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Useful Dictionary Methods\n", "\n", "We are going to see in the next couple of notebooks how to systematically access values in a dictionary (amongst other things). For now, let's also take in the fact the dictionaries _also_ have utility *methods* similar to what we saw with the `list`. And as with the list, these methods are functions that only make sense _when_ you're working with a dictionary, so they're bundled up in a way that makes them easy to use.\n", "\n", "Let's say that you have forgotten what *keys* you put in your dictionary..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "programmers = {\n", " \"Charles\": \"Babbage\",\n", " \"Ada\": \"Lovelace\",\n", " \"Alan\": \"Turing\"\n", "}\n", "\n", "print(programmers.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or maybe you just need to access all of the values without troubling to ask for each key:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(programmers.values())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or maybe you even need to get them as pairs:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Output is a list of key-value pairs!\n", "print(programmers.items())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### A challenge for you\n", "\n", "Can you access all the values of `capitalDict` from the previous challenge?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(???)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(capitalDict.values())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Are You On the List? (Part 2)\n", "\n", "As with the `list` data type, you can check the presence or absence of a key in a dictionary, using the *in* / *not in* operators... but note that they only work on keys." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Charles\" in programmers)\n", "print(\"Babbage\" in programmers)\n", "print(True not in programmers)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### What Do You Do if You're Not On the List?\n", "\n", "One challenge with dictionaries is that sometimes we have no real idea if a key exists or not. With a list, it's pretty easy to figure out whether or not an index exists because we can just ask Python to tell us the _length_ of the list. So that makes it fairly easy to avoid having the list 'blow up' by throwing an exception.\n", "\n", "It's rather harder for a dictionary though, so that's why we have the dedicated **`get()`** method: it not only allows us to fetch the *value* associated with a *key*, it also allows us to specify a default value in case the key does not exist:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(programmers.get(\"Lady Ada\", \"Are you sure you spelled that right?\") )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See how this works: the key doesn't exist, but unlike what happened when we asked for `myDict[99]` we don't get an exception, we get the default value specified as the _second_ input to the method `get`. \n", "\n", "So you've learned two things here: that functions can take more than one input (this one takes both the key that we're looking for, and value to return if Python can't find the key); and that different types (or classes) of data have different methods (there's no `get` for lists)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lists of Lists, Dictionaries of Lists, Dictionaries of Dictionaries... Oh my!\n", "\n", "OK, this is where it's going to get a little weird but you're also going to see how programming is a little like Lego: once you get the building blocks, you can make lots of cool/strange/useful contraptions from some pretty simple concepts.\n", "\n", "Remember that a list or dictionary can store _anything_: so the first item in your list could itself _be_ a list! For most people starting out on programming, this is the point where their brain starts hurting (it happened to us) and you might want to throw up your hands in frustration thinking \"I'm never going to understand this!\" But if you stick with it, you will. \n", "\n", "And this is really the start of the power of computation.\n", "\n", "### A Data Set of City Attributes\n", "\n", "Let's start out with what some (annoying) people would call a 'trivial' example of how a list-of-lists (LoLs, though most people aren't laughing) can be useful. Let's think through what's going on below: what happens if we write `cityData[0]`?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Format: city, country, population, area (km^2)\n", "cityData = [\n", " ['London','U.K.',8673713,1572],\n", " ['Paris','France',2229621,105],\n", " ['Washington, D.C.','U.S.A.',672228,177],\n", " ['Abuja','Nigeria',1235880,1769],\n", " ['Beijing','China',21700000,16411],\n", "]\n", "\n", "print(cityData[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So how would we access something inside the list returned from `cityData[0]`?\n", "\n", "Why not try:\n", "```python\n", "cityData[0][1]\n", "```\n", "See if you can figure out how to retrieve and print the following from `cityData`:\n", "1. France\n", "2. 16411\n", "3. Washington, D.C.\n", "\n", "Type the code into the coding area below..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(cityData[1][1])\n", "print(cityData[4][3])\n", "print(cityData[2][0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### A challenge for you\n", "Can you retrieve and print the following from `cityData`:\n", "1. Nigeria\n", "2. 8673713\n", "3. 177" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(???)\n", "print(???)\n", "print(???) " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(cityData[3][1])\n", "print(cityData[0][2])\n", "print(cityData[2][3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A Phonebook+\n", "\n", "So that's an LoL (list-of-lists). Let's extend this idea to what we'll call Phonebook+ which will be a DoL (dictionary-of-lists). In other words, a phonebook that can _do more_ than just give us phone numbers! We're going to build on the emergency phonebook example above." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# American Emergency Number: 911\n", "# British Emergency Number: 999\n", "# Icelandic Emergency Number: 112\n", "# French Emergency Number: 112\n", "# Russian Emergency Number: 102\n", "eNumbers = {\n", " 'IS': ['Icelandic',112],\n", " 'US': ['American',911],\n", " 'FR': ['French',112],\n", " 'RU': ['Russian',102],\n", " 'UK': ['British',999]\n", "}\n", "print(\"The \" + eNumbers['IS'][0] + \" emergency number is \" + str(eNumbers['IS'][1]))\n", "print(\"The \" + eNumbers['US'][0] + \" emergency number is \" + str(eNumbers['US'][1]))\n", "print(\"The \" + eNumbers['FR'][0] + \" emergency number is \" + str(eNumbers['FR'][1]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### A Challenge for you\n", "\n", "See if you can create the rest of the `eNumbers` dictionary and then print out the Russian and British emergency numbers." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(\"The \" + ??? + \" emergency number is \" + ???)\n", "print(\"The \" + ??? + \" emergency number is \" + ???) " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(\"The \" + eNumbers['RU'][0] + \" emergency number is \" + str(eNumbers['RU'][1]))\n", "print(\"The \" + eNumbers['UK'][0] + \" emergency number is \" + str(eNumbers['UK'][1]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dictionary-of-Dictionaries\n", "\n", "OK, this is the last thing we're going to throw at you today – getting your head around 'nested' lists and dictionaries is _hard_. Really hard. But it's the all-important first step to thinking about data the way that computer 'thinks' about it. This is really abstract: something that you access by keys, which in turn gives you access to other keys... it's got a name: recursion. And it's probably one of the cleverest things about computing. \n", "\n", "Here's a bit of a complex DoD, combined with a DoL, and other nasties:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cityData2 = {\n", " 'London' : {\n", " 'population': 8673713,\n", " 'area': 1572, \n", " 'location': [51.507222, -0.1275],\n", " 'country': {\n", " 'ISO2': 'UK',\n", " 'Full': 'United Kingdom',\n", " },\n", " },\n", " 'Paris' : {\n", " 'population': 2229621,\n", " 'area': 105.4,\n", " 'location': [48.8567, 2.3508],\n", " 'country': {\n", " 'ISO2': 'FR',\n", " 'Full': 'France',\n", " },\n", " }\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try the following code in the code cell below:\n", "```python\n", "print(cityData2['Paris'])\n", "print(cityData2['Paris']['country']['ISO2'])\n", "print(cityData2['Paris']['location'][0])\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "#your code here" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(cityData2['Paris'])\n", "print(cityData2['Paris']['country']['ISO2'])\n", "print(cityData2['Paris']['location'][0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, figure out how to print:\n", "`The population of Paris, the capital of France (FR), is 2229621.`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(\"The population of Paris, the capital of \" + str(cityData2['Paris']['country']['Full']) + \" \" \\\n", " + \"(\" + ??? + \") \" + \"is \"+ ??? + \".\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(\"The population of Paris, the capital of \" + str(cityData2['Paris']['country']['Full']) + \" \" \\\n", " + \"(\" + str(cityData2['Paris']['country']['ISO2']) + \") \" + \"is \"+ str(cityData2['Paris']['population']) + \".\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And print `It has a density of 21153.899 persons per square km.` \n", "**Hint**: to calculate density, divide population with area." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(\"It has a density of \" + ???)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(\"It has a density of \" + str(cityData2['Paris']['population'] / cityData2['Paris']['area'] ))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Do the same for London." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "print(???)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "# Note that we can tweak the formatting a bit: Python is smart \n", "# enough to understand that if you have a '+' on the end of a\n", "# string and there next line is also a string then it'll \n", "# continue to concatenate the string...\n", "print(\"The population of \" + 'London' + \", the capital of \" + \n", " cityData2['London']['country']['Full'] + \" (\" + cityData2['London']['country']['ISO2'] + \"), is \" + \n", " str(cityData2['London']['population']) + \". It has a density of \" + \n", " str(cityData2['London']['population']/cityData2['London']['area']) + \" persons per square km\")\n", "\n", "# But a _better_ way to do this might be one in which we don't\n", "# hard-code 'London' into the output -- by changing the variable\n", "# 'c' to Paris we can change the output completely...\n", "c = 'Paris'\n", "cd = cityData2[c]\n", "print(\"The population of \" + c + \", the capital of \" + \n", " cd['country']['Full'] + \" (\" + cd['country']['ISO2'] + \"), is \" + \n", " str(cd['population']) + \". It has a density of \" + \n", " \"{0:8.1f}\".format(cd['population']/cd['area']) + \" persons per square km\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Code (Applied Geo-example)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's continue our trips around the world! This time though, we'll do things better, and instead of using a simple URL, we are going to use a real-word geographic data type, that you can use on a web-map or in your favourite GIS software.\n", "\n", "If you look down below at the `KCL_position` variable you'll see that we're assigning it a complex and scary data structure. Don't be afraid! If you look closely enough you will notice that is just made out the \"building blocks\" that we've seen so far: `floats`, `lists`, `strings`..all wrapped comfortably in a cosy `dictionary`!\n", "\n", "This is simply a formalised way to represent a *geographic marker* (a pin on the map!) in a format called `GeoJSON`.\n", "\n", "According to the awesome [Lizy Diamond](https://twitter.com/lyzidiamond?lang=en-gb) \n", "\n", ">[GeoJSON](http://geojson.org/geojson-spec.html) is an open and popular geographic data format commonly used in web applications. It is an extension of a format called [JSON](http://json.org), which stands for *JavaScript Object Notation*. Basically, JSON is a table turned on its side. GeoJSON extends JSON by adding a section called \"geometry\" such that you can define coordinates for the particular object (point, line, polygon, multi-polygon, etc). A point in a GeoJSON file might look like this:\n", "\n", " {\n", " \"type\": \"Feature\",\n", " \"geometry\": {\n", " \"type\": \"Point\",\n", " \"coordinates\": [\n", " -122.65335738658904,\n", " 45.512083676585156\n", " ]\n", " },\n", " \"properties\": {\n", " \"name\": \"Hungry Heart Cupcakes\",\n", " \"address\": \"1212 SE Hawthorne Boulevard\",\n", " \"website\": \"http://www.hungryheartcupcakes.com\",\n", " \"gluten free\": \"no\"\n", " }\n", " }\n", " \n", ">GeoJSON files have to have both a `\"geometry\"` section and a `\"properties\"` section. The `\"geometry\"` section houses the geographic information of the feature (its location and type) and the `\"properties\"` section houses all of the descriptive information about the feature (like fields in an attribute table). [Source](https://github.com/lyzidiamond/learn-geojson)\n", "\n", "\n", "Now, in order to have our first \"webmap\", we have to re-create such `GeoJSON` structure. \n", "\n", "As you can see there are two variables containing King's College Longitude/Latitude coordinate position. Unfortunately, they are in the wrong data type. Also, the variable `longitude` is not included in the list `KCLCoords` and the list itself is not assigned as a value to the `KCLGeometry`dictionary.\n", "\n", "Take all the necessary steps to fix the code, using the functions we've seen so far.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Don't worry about the following lines\n", "# I'm simply requesting some modules to\n", "# have additional functions at my disposal\n", "# which usually are not immediately available\n", "import json\n", "from ipyleaflet import Map, GeoJSON, basemaps\n", "\n", "# King's College coordinates\n", "# What format are they in? Does it seem appropriate?\n", "# How would you convert them back to numbers?\n", "longitude = -0.11596798896789551\n", "latitude = 51.51130657591914\n", "\n", "# Set this up as a coordinate pair \n", "KCL_Coords = [longitude, latitude ]\n", "\n", "# How can you assign KCLCoords to \n", "# the key KCLGeometry[\"coordinates\"]?\n", "KCL_Geometry = {\n", " \"type\": \"Point\",\n", "\n", " \"coordinates\": KCL_Coords\n", " }\n", "\n", "KCL_Position = {\n", " \"type\": \"FeatureCollection\",\n", " \"features\": [\n", " {\n", " \"type\": \"Feature\",\n", " \"properties\": {\n", " \"marker-color\": \"#7e7e7e\",\n", " \"marker-size\": \"medium\",\n", " \"marker-symbol\": \"building\",\n", " \"name\": \"KCL\"\n", " },\n", " \"geometry\": KCL_Geometry\n", " }\n", " ]\n", "}\n", "\n", "# OUTPUT\n", "# -----------------------------------------------------------\n", "# I'm justing using the \"imported\" module to print the output\n", "# in a nice and formatted way\n", "print(json.dumps(KCL_Position, indent=4))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# We can also show this in Jupyter directly \n", "# (it won't show up in the PDF version though)\n", "m = Map(center = (51.51, -0.10), zoom=12, min_zoom=5, max_zoom=20, \n", " basemap=basemaps.OpenTopoMap)\n", "geo = GeoJSON(data=KCL_Position)\n", "m.add_layer(geo)\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And here we request a remote GeoJSON file (from `url`), convert to a dictionary, and place it in a map as a new layer." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "import random\n", "import requests\n", "\n", "from ipyleaflet import Map, GeoJSON\n", "\n", "url = 'https://github.com/jupyter-widgets/ipyleaflet/raw/master/examples/europe_110.geo.json'\n", "r = requests.get(url)\n", "d = r.content.decode(\"utf-8\")\n", "j = json.loads(d)\n", "\n", "def random_color(feature):\n", " return {\n", " 'color': 'black',\n", " 'fillColor': random.choice(['red', 'yellow', 'green', 'orange']),\n", " }\n", "\n", "m = Map(center=(50.6252978589571, 0.34580993652344), zoom=3)\n", "\n", "geo_json = GeoJSON(\n", " data=j,\n", " style={\n", " 'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.1, 'weight': 1\n", " },\n", " hover_style={\n", " 'color': 'white', 'dashArray': '0', 'fillOpacity': 0.5\n", " },\n", " style_callback=random_color\n", ")\n", "m.add_layer(geo_json)\n", "\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As proof that behind this all is just a dictionary:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(json.dumps(j, indent=4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After you've run the code, Python will have saved a file called `my-first-marker.geojson` in the folder where you are running the notebook. Try to upload it on [this website (Geojson.io)](http://geojson.io/#map=2/20.0/0.0) and check it shows a marker _somewhere_ in central London... " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "### Further references:\n", "\n", "General list or resources\n", "- [Awesome list of resources](https://github.com/vinta/awesome-python)\n", "- [Python Docs](https://docs.python.org/2.7/tutorial/introduction.html)\n", "- [HitchHiker's guide to Python](http://docs.python-guide.org/en/latest/intro/learning/)\n", "- [Python for Informatics](http://www.pythonlearn.com/book_007.pdf)\n", "- [Learn Python the Hard Way - Lists](http://learnpythonthehardway.org/book/ex32.html)\n", "- [Learn Python the Hard Way - Dictionaries](http://learnpythonthehardway.org/book/ex39.html)\n", "- [CodeAcademy](https://www.codecademy.com/courses/python-beginner-en-pwmb1/0/1)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Credits!\n", "\n", "#### Contributors:\n", "The following individuals have contributed to these teaching materials: \n", "- [James Millington](https://github.com/jamesdamillington)\n", "- [Jon Reades](https://github.com/jreades)\n", "- [Michele Ferretti](https://github.com/miccferr)\n", "- [Zahratu Shabrina](https://github.com/zarashabrina)\n", "\n", "#### License\n", "The content and structure of this teaching project itself is licensed under the [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 license](https://creativecommons.org/licenses/by-nc-sa/4.0/), and the contributing source code is licensed under [The MIT License](https://opensource.org/licenses/mit-license.php).\n", "\n", "#### Acknowledgements:\n", "Supported by the [Royal Geographical Society](https://www.rgs.org/HomePage.htm) (with the Institute of British Geographers) with a Ray Y Gildea Jr Award.\n", "\n", "#### Potential Dependencies:\n", "This notebook may depend on the following libraries: None" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }