{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Assignment 9: Geographic visualization with Mapbox Studio\n", "\n", "In this assignment, the second-to-last of the semester, we will venture outside of the Python ecosystem to create interactive maps with Mapbox Studio. You'll be making an interactive map of public intoxication violations in Fort Worth, drawn from the same City crime dataset you worked with in Assignment 7. You'll explore methods for visualizing large amounts of point data and customize your map's appearance.. \n", "\n", "In this instance, you are going to upload a bulk CSV download that I've prepared for you from the City's open data catalog. The data as currently constituted are not quite ready for use in Mapbox Studio, so we're going to clean it up a bit in `pandas` first. \n", "\n", "Mapbox Studio accepts data in many formats, such as CSV, GeoJSON, and zipped shapefile. In this instance, our data are in CSV format. Let's read the data into `pandas` and have a look. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Case and OffenseCase NumberReported DateNature Of CallFrom DateOffenseDescriptionBlock AddressCityStateBeatDivisionCouncil DistrictAttempt CompleteLocation TypeLocation DescriptionLocation
0200025542-90E20002554203/28/2020PUBLIC INTOXICATION03/28/2020 11:50:00 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...200 NE 28TH STFORT WORTHTXC11Northwest2.0C1818 PARKING LOT/GARAGE(32.79512267527676, -97.34736968390531)
1200025291-90E20002529103/27/2020PUBLIC INTOXICATION03/27/2020 08:29:28 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...14300 CENTREPORT LANDING CIRFORT WORTHTXH17NaNNaNC2020 RESIDENCE/HOME(32.81901915935712, -97.05732878148257)
2200025472-35A20002547203/28/2020PUBLIC INTOXICATION03/28/2020 04:41:22 PM35AHSC 481.117(B) Poss CS PG 3 <28G 35A DRUG/NARC...5400 ENCLAVE CIRFORT WORTHTXK18NaNNaNC1515 JAIL/PRISON(32.67383727899393, -97.41089914948881)
3200025309-90E20002530903/27/2020PUBLIC INTOXICATION03/27/2020 09:11:59 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...3300 W BOYCE AVEFORT WORTHTXJ12South9.0C2020 RESIDENCE/HOME(32.68139719413715, -97.36576854742505)
4200025525-90E20002552503/28/2020PUBLIC INTOXICATION03/28/2020 10:54:17 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...100 E BOLT STFORT WORTHTXI11NaNNaNC1313 HIGHWAY/ROAD/ALLEY(32.68865080126258, -97.3265765609558)
\n", "
" ], "text/plain": [ " Case and Offense Case Number Reported Date Nature Of Call \\\n", "0 200025542-90E 200025542 03/28/2020 PUBLIC INTOXICATION \n", "1 200025291-90E 200025291 03/27/2020 PUBLIC INTOXICATION \n", "2 200025472-35A 200025472 03/28/2020 PUBLIC INTOXICATION \n", "3 200025309-90E 200025309 03/27/2020 PUBLIC INTOXICATION \n", "4 200025525-90E 200025525 03/28/2020 PUBLIC INTOXICATION \n", "\n", " From Date Offense \\\n", "0 03/28/2020 11:50:00 PM 90E \n", "1 03/27/2020 08:29:28 PM 90E \n", "2 03/28/2020 04:41:22 PM 35A \n", "3 03/27/2020 09:11:59 PM 90E \n", "4 03/28/2020 10:54:17 PM 90E \n", "\n", " Description \\\n", "0 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "1 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "2 HSC 481.117(B) Poss CS PG 3 <28G 35A DRUG/NARC... \n", "3 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "4 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "\n", " Block Address City State Beat Division \\\n", "0 200 NE 28TH ST FORT WORTH TX C11 Northwest \n", "1 14300 CENTREPORT LANDING CIR FORT WORTH TX H17 NaN \n", "2 5400 ENCLAVE CIR FORT WORTH TX K18 NaN \n", "3 3300 W BOYCE AVE FORT WORTH TX J12 South \n", "4 100 E BOLT ST FORT WORTH TX I11 NaN \n", "\n", " Council District Attempt Complete Location Type Location Description \\\n", "0 2.0 C 18 18 PARKING LOT/GARAGE \n", "1 NaN C 20 20 RESIDENCE/HOME \n", "2 NaN C 15 15 JAIL/PRISON \n", "3 9.0 C 20 20 RESIDENCE/HOME \n", "4 NaN C 13 13 HIGHWAY/ROAD/ALLEY \n", "\n", " Location \n", "0 (32.79512267527676, -97.34736968390531) \n", "1 (32.81901915935712, -97.05732878148257) \n", "2 (32.67383727899393, -97.41089914948881) \n", "3 (32.68139719413715, -97.36576854742505) \n", "4 (32.68865080126258, -97.3265765609558) " ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "# Modify the path below to your data path\n", "df = pd.read_csv(\"data/fort_worth_crime_extract.csv\")\n", "\n", "df.head()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Scroll to the right-hand side of your data frame to view the `Location` column. You'll notice that it is formatted as latitude/longitude coordinate pairs, separated by a comma and enclosed in parentheses. Additionally, some of the latitude/longitude values are missing. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "False 1979\n", "True 44\n", "Name: Location, dtype: int64" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "null_rows = pd.isnull(df.Location)\n", "\n", "null_rows.value_counts()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "It looks like 44 rows in our dataset are missing latitude and longitude information. In a regular data analysis workflow, you'd want to do some investigation of these missing values, and ultimately see if there is any systematic bias there. Another option would be to try to locate as many of these missing values as possible. As our focus here is learning mapping in Mapbox Studio, however, let's forge ahead. \n", "\n", "To map CSV data, Mapbox Studio requires that one column contain the longitude coordinates, and one column contain the latitude coordinates. As such, we'll need to get rid of the parentheses in the column, then split the column into two columns, and finally add those columns back to our data frame. Study the code below to examine what it does: " ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ ":3: FutureWarning: The default value of regex will change from True to False in a future version. In addition, single character regular expressions will*not* be treated as literal strings when regex=True.\n", " df['Location'] = df.Location.str.replace(char, '')\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Case and OffenseCase NumberReported DateNature Of CallFrom DateOffenseDescriptionBlock AddressCityStateBeatDivisionCouncil DistrictAttempt CompleteLocation TypeLocation DescriptionLocationlatitudelongitude
0200025542-90E20002554203/28/2020PUBLIC INTOXICATION03/28/2020 11:50:00 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...200 NE 28TH STFORT WORTHTXC11Northwest2.0C1818 PARKING LOT/GARAGE32.79512267527676, -97.3473696839053132.79512267527676-97.34736968390531
1200025291-90E20002529103/27/2020PUBLIC INTOXICATION03/27/2020 08:29:28 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...14300 CENTREPORT LANDING CIRFORT WORTHTXH17NaNNaNC2020 RESIDENCE/HOME32.81901915935712, -97.0573287814825732.81901915935712-97.05732878148257
2200025472-35A20002547203/28/2020PUBLIC INTOXICATION03/28/2020 04:41:22 PM35AHSC 481.117(B) Poss CS PG 3 <28G 35A DRUG/NARC...5400 ENCLAVE CIRFORT WORTHTXK18NaNNaNC1515 JAIL/PRISON32.67383727899393, -97.4108991494888132.67383727899393-97.41089914948881
3200025309-90E20002530903/27/2020PUBLIC INTOXICATION03/27/2020 09:11:59 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...3300 W BOYCE AVEFORT WORTHTXJ12South9.0C2020 RESIDENCE/HOME32.68139719413715, -97.3657685474250532.68139719413715-97.36576854742505
4200025525-90E20002552503/28/2020PUBLIC INTOXICATION03/28/2020 10:54:17 PM90EGC 080 Public Intoxication 90E DRUNKENNESS 000...100 E BOLT STFORT WORTHTXI11NaNNaNC1313 HIGHWAY/ROAD/ALLEY32.68865080126258, -97.326576560955832.68865080126258-97.3265765609558
\n", "
" ], "text/plain": [ " Case and Offense Case Number Reported Date Nature Of Call \\\n", "0 200025542-90E 200025542 03/28/2020 PUBLIC INTOXICATION \n", "1 200025291-90E 200025291 03/27/2020 PUBLIC INTOXICATION \n", "2 200025472-35A 200025472 03/28/2020 PUBLIC INTOXICATION \n", "3 200025309-90E 200025309 03/27/2020 PUBLIC INTOXICATION \n", "4 200025525-90E 200025525 03/28/2020 PUBLIC INTOXICATION \n", "\n", " From Date Offense \\\n", "0 03/28/2020 11:50:00 PM 90E \n", "1 03/27/2020 08:29:28 PM 90E \n", "2 03/28/2020 04:41:22 PM 35A \n", "3 03/27/2020 09:11:59 PM 90E \n", "4 03/28/2020 10:54:17 PM 90E \n", "\n", " Description \\\n", "0 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "1 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "2 HSC 481.117(B) Poss CS PG 3 <28G 35A DRUG/NARC... \n", "3 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "4 GC 080 Public Intoxication 90E DRUNKENNESS 000... \n", "\n", " Block Address City State Beat Division \\\n", "0 200 NE 28TH ST FORT WORTH TX C11 Northwest \n", "1 14300 CENTREPORT LANDING CIR FORT WORTH TX H17 NaN \n", "2 5400 ENCLAVE CIR FORT WORTH TX K18 NaN \n", "3 3300 W BOYCE AVE FORT WORTH TX J12 South \n", "4 100 E BOLT ST FORT WORTH TX I11 NaN \n", "\n", " Council District Attempt Complete Location Type Location Description \\\n", "0 2.0 C 18 18 PARKING LOT/GARAGE \n", "1 NaN C 20 20 RESIDENCE/HOME \n", "2 NaN C 15 15 JAIL/PRISON \n", "3 9.0 C 20 20 RESIDENCE/HOME \n", "4 NaN C 13 13 HIGHWAY/ROAD/ALLEY \n", "\n", " Location latitude \\\n", "0 32.79512267527676, -97.34736968390531 32.79512267527676 \n", "1 32.81901915935712, -97.05732878148257 32.81901915935712 \n", "2 32.67383727899393, -97.41089914948881 32.67383727899393 \n", "3 32.68139719413715, -97.36576854742505 32.68139719413715 \n", "4 32.68865080126258, -97.3265765609558 32.68865080126258 \n", "\n", " longitude \n", "0 -97.34736968390531 \n", "1 -97.05732878148257 \n", "2 -97.41089914948881 \n", "3 -97.36576854742505 \n", "4 -97.3265765609558 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Loop through the characters in the string we want to replace, and replace them in turn\n", "for char in ['(', ')']: \n", " df['Location'] = df.Location.str.replace(char, '')\n", "\n", "# Split our `Location_1` column at the comma with the `.split()` method;\n", "# the `expand = True` argument returns a new data frame\n", "locs = df.Location.str.split(',', expand = True)\n", "\n", "locs.columns = ['latitude', 'longitude']\n", "\n", "# Add these new columns to our existing data frame with the\n", "# `pd.concat` method, to which we pass a list of data frames;\n", "# specifying `axis = 1` makes sure that we combine columns, not\n", "# rows.\n", "df2 = pd.concat([df, locs], axis = 1)\n", "\n", "df2.head()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Success! We can now write our location-aware data frame to a CSV, for use in Mapbox Studio. " ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "df2.to_csv('intoxication.csv', index = False)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "When you run this cell, `pandas` will write a CSV file named `intoxication.csv` in your top-level directory in Colab. Go find it by clicking the folder icon and expand its options; you'll get an option to download the file to the computer, which should default to your Downloads directory. \n", "\n", "Let's now head over to Mapbox Studio at http://studio.mapbox.com. \n", "\n", "## Setting up a Style in Mapbox Studio\n", "\n", "If you don't yet have a Mapbox Studio account, go ahead and sign up for one by clicking the \"Sign up for Mapbox\" link from the \"Sign in\" screen. All you need to do is specify a username, email address, and password and agree to the Terms of Service, and you are good to go. Once you've established your account, you'll be taken to the Mapbox Studio splash screen, which defaults to the \"Styles\" tab. You won't see any styles as you haven't created any yet. Click the \"New style\" button to get started. \n", "\n", "\n", "\n", "View the different templates available to you. Given that we are plotting data over a basemap layer, I'd recommend using a template with more muted colors; I have a preference for the \"Monochrome - Light\" version given the way we'll be visualizing our data but I'll let you choose the template you like best. Once you've selected a basemap template, click the \"Customize\" button to advance to the Mapbox Studio editor. \n", "\n", "\n", "\n", "In the map editor, pan over to the Fort Worth area and zoom in and out. Mapbox Studio gives you access to _vector tiles_, which are variants of the tiled mapping structure we've discussed in class but which expose the underlying data rather than simply showing images. This allows for the customization of any component of the map. You'll see a series of such \"components\" on the left-hand side of the screen. They are organized into categories which you can explore and edit collectively. Alternatively, you can view major categories and style them by clicking the \"Colors\" option in the lower left section of the screen and choosing a map element, then selecting a color from the interactive picker. You can also click the \"Layers\" tab to view all of the individual map layers, and edit them one-by-one; you may need to \"override\" the color to do so. Below, I show an example of the \"Monochrome - Light\" template where I've styled water features with a light blue and park features with a light green. Experiment and try designing a map yourself!\n", "\n", "![customized map](img/map1.png)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Loading new data into Mapbox Studio\n", "\n", "Now that you've spent some time exploring Mapbox Studio and customizing your map, let's add the public drunkenness data to the map as well to visualize it. Follow these steps to upload your data and add it to the map: \n", "\n", "1. Click \"Layers\" on the left-hand side of the screen and look for the plus sign icon. This will bring up the \"New layer\" menu. \n", "2. Look for the \"Upload data\" option and click there. Locate your intoxication CSV file and drag and drop it on the dialog box, or click on \"Select a file\" and navigate to it on your computer. You'll see the \"New tileset\" dialog appear; click __Confirm__ if the information is correct.\n", "3. You'll see a \"Notifications\" box appear in the lower left corner of the screen, letting you know that your upload is processing. Mapbox Studio is converting your public intoxication dataset into vector tiles, which is the same format that is used by the rest of the layers that you've been working with. This will allow you to display your data along with those other layers on the map.\n", "4. Once your upload has finished processing, scroll down the list of \"Sources\" to the bottom. You should see your intoxication tile source appear as an option. Click there to reveal the point layer within the tileset, then click the revealed layer to add it to your map. You should see your points added to your map. \n", "\n", "\n", "\n", "
\n", "
\n", "\n", "Once you've successfully added your tileset, click \"Style\" as instructed on the screen to style your layer. " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Modifying visualization options for your tileset\n", "\n", "By default, your points will show up as black dots on top of your basemap. While this does show clusters of violations around the city, it is not the most visually pleasing representation of your data. Let's make some modifications to the data representation to show it in an alternative way. Feel free to experiment with different style options; you can modify the circle radius, the color, blur and opacity, and other characteristics. \n", "\n", "You are not limited to styling your point data as circles, however. Click the \"Select data\" option once more (ensuring first that your intoxication layer is still selected) and click the __Type__ option. From the options that appear, choose __Heatmap__. Now, click __Style__ once more to style your data as a heatmap. You'll note that your data no longer appears as points, but as a smoothed representation of where your points are concentrated. My default view is the image below; yours may appear slightly different depending on how far you are currently zoomed in.\n", "\n", "\n", "\n", "The visualization defaults to a blue-to-red representation based on five colors, which each represent different density values. The highest density value is scaled to 1, which is bright red; the lowest color value is 0.1 by default, colored blue. Areas without violations are represented without color. Try zooming in and out on your map to see how the heatmap changes based on zoom level. \n", "\n", "There are several ways we can make the map more legible, however; I'll outline a few here. \n", "\n", "1. When zoomed out to show the entire city, the high-density areas cover most of the urban core. This limits our ability to show differentiation on the map. To modify this, change the __Radius__ of your heatmap from the default 30 pixels and make it smaller. Experiment with different radii and observe how the data representation changes on your map.\n", "\n", "2. The default color representation, while mapping to perceptions of \"hot\" and \"cold\" is not colorblindness-safe. Make some changes to the color values to use a colorblind-safe palette. I recommend the __viridis__ family of color palettes, which are built into __seaborn__ for quick lookup. There are five palettes in the viridis family: `viridis`, `magma`, `inferno`, `plasma`, and `cividis`. All are color-blind safe, perceptually uniform, and safe to print in black and white. Let's load in the palettes and take a look at them:\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import seaborn as sns\n", "\n", "viridis = sns.color_palette(\"viridis\", 5).as_hex()\n", "inferno = sns.color_palette(\"inferno\", 5).as_hex()\n", "magma = sns.color_palette(\"magma\", 5).as_hex()\n", "plasma = sns.color_palette(\"plasma\", 5).as_hex()\n", "cividis = sns.color_palette(\"cividis\", 5).as_hex()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "I've assigned five-color extracts from the palettes and converted them to hexadecimal representation, which is a common way to represent colors and can be used in Mapbox Studio. Let's take a look at each palette in turn:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['#443983', '#31688e', '#21918c', '#35b779', '#90d743']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAACQCAYAAAAoVz7mAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAABYlAAAWJQFJUiTwAAADvElEQVR4nO3csYpcZRiA4f+Mm7DDQorR7TeNaKOFhRdi6RV4L15ZwEIIYhW3sEmxIpGFSLL5bbyBfT0zxyHP00z1f3zwM4eXMzDLnHMAAPA4u60XAAA4RyIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACC7WHrgsy29jjGdjjNu1ZwMArOxmjPFmzvn8sQdXj6gxxrPd7snhan99OMJsTuD93gvKc/VwObdegf/g4vJh6xWIDk/vt16B6PWr+/Hu7Yd09hgRdXu1vz58+9UPRxjNKdx9fbX1CkR/ftkeBPw/fPb53dYrEH1/82LrFYh+/O7F+P2Xv27LWa8cAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQLHPOdQcuy91u9+Rwtb9edS6n836vrc/Vw+W632dO6+LyYesViA5P77degej1q/vx7u2HP+acnz727DEi6u8xxidjjJ9XHcypfPHv56+bbkHl/s6Xuztv7u983Ywx3sw5nz/24MX6u4yXY4wx5/zmCLM5smVZfhrD/Z0r93e+3N15c38fJ7/bAAAEIgoAIBBRAACBiAIACEQUAECw+l8cAAB8DLyJAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgOAfCtlZGKiX8AUAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "execution_count": 6, "metadata": { "image/png": { "height": 72, "width": 296 }, "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# viridis\n", "print(viridis)\n", "sns.palplot(viridis)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['#320a5e', '#781c6d', '#bc3754', '#ed6925', '#fbb61a']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAACQCAYAAAAoVz7mAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAABYlAAAWJQFJUiTwAAADt0lEQVR4nO3csWpcVxRA0fs0MsgqRmZSprG7pEwC+YKQKvmV/GkIhhQqAha4SBHswhCEGPBNkx/Q1hs9Bq/VTHUPB06zGYZZ5pwDAIDHudh6AQCAcySiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgOBy7YHLsrwbY+zHGHdrzwYAWNnrMcanOeebxz5cPaLGGPtl7A5Xy83hBLN5BvvL3dYrEO1fHLdegSe4vr7fegWii1eft16B6Pb9cdw/tLeniKi7q+Xm8O3LX04wmufw8+Fm6xWIfvr6761X4Am++/7t1isQ7X/9d+sViH787Z/xx1/Hu/LWb6IAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABAsc851By7Lh2XsDlfLzapzeT77y93WKxDtXxy3XoEnuL6+33oFootXn7degej2/XHcP4yPc86vHvv2FBH1MMbYjTHerjqY5/LN/5+3m25B5X7ny+3Om/udr9djjE9zzjePfXi5/i7jzzHGmHP+cILZnNiyLL+P4X7nyv3Ol9udN/f7MvlNFABAIKIAAAIRBQAQiCgAgEBEAQAEq//FAQDAl8A3UQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABD8B4KVUR32MxU5AAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "execution_count": 7, "metadata": { "image/png": { "height": 72, "width": 296 }, "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# inferno\n", "print(inferno)\n", "sns.palplot(inferno)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['#2c115f', '#721f81', '#b73779', '#f1605d', '#feb078']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAACQCAYAAAAoVz7mAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAABYlAAAWJQFJUiTwAAADuklEQVR4nO3csYpcZRiA4f94NiwhOANrI9gkYqG1VvbaCV6LN+QVRRCEpIpbbGOxFmmiS+C38Qb2zZk5DHmeZqr/44OPgZdl2GXOOQAAeJxP9l4AAOASiSgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAguNp64LIsf44xDmOM261nAwBs7PkY4+2c88VjH24eUWOMwzLWm+v1eHOC2ZzBYb3eewWiw9XcewU+wLOnD3uvQLQen+y9AtGru/vx7uF9enuKiLq9Xo83Xx1+OsFozuHHw5d7r0D0w+f/7L0CH+D7b+72XoHo05+/2HsFou9++XX89uav2/LWb6IAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABAsc85tBy7L/TLWm+v1uOlczuewXu+9AtHhatvvM+f17OnD3isQrccne69A9Orufrx7eP/3nPOzx749RUT9O8ZYxxi/bzqYc/n6/8/Xu25B5X6Xy+0um/tdrudjjLdzzhePfXi1/S7jjzHGmHN+e4LZnNiyLC/HcL9L5X6Xy+0um/t9nPwmCgAgEFEAAIGIAgAIRBQAQCCiAACCzf/FAQDAx8BfogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACD4Dx33UB0ABS6iAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "execution_count": 8, "metadata": { "image/png": { "height": 72, "width": 296 }, "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# magma\n", "print(magma)\n", "sns.palplot(magma)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['#5c01a6', '#9c179e', '#cc4778', '#ed7953', '#fdb42f']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAACQCAYAAAAoVz7mAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAABYlAAAWJQFJUiTwAAADtUlEQVR4nO3cMYtcVRiA4XOdJYFJyMqm2yrbWQbFysbaP+O/8N8pCEIkKi6k1iLN7qY5Nv6BfffOXC55nmaqc/jgG7gvw2WWOecAAOBxvth6AACAPRJRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQHCx9oXLsvw9xng1xrhd+24AgJW9GWN8nHPePPbg6hE1xnh1GM+uLsf11Qnu5gxeXsytRyA6Hu+3HoEneH582HoEosMLu9urdx/ux92n9tw7RUTdXo7rqx+Wn05wNefw/WsP4r16+/b91iPwBDdf/7H1CERffvfn1iMQffvj+/HLX3e35ax3ogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAECxzznUvXJZ/DuPZ1eW4XvVezuflxbrfCc7neLzfegSe4PnxYesRiA4v7G6v3n24H3ef5r9zztePPXuKiHoYYxzGGL+uejHn8tX/n79vOgWV/e2X3e2b/e3XmzHGxznnzWMPXqw/y/htjDHmnN+c4G5ObFmWn8ewv72yv/2yu32zv8+Td6IAAAIRBQAQiCgAgEBEAQAEIgoAIFj9Lw4AAD4HfokCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACA4D+eUlYV+xTmDwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "execution_count": 9, "metadata": { "image/png": { "height": 72, "width": 296 }, "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# plasma\n", "print(plasma)\n", "sns.palplot(plasma)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['#2a3f6d', '#575d6d', '#7d7c78', '#a59c74', '#d2c060']\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAACQCAYAAAAoVz7mAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAABYlAAAWJQFJUiTwAAADrklEQVR4nO3csWocVxSA4TuK0EoKGKT0sWxMcOPKD5M8QV4wz5EiYEhII7m3g3Flgc114xfQn1kNg7+v2eoeDlyW/WeKXeacAwCAhznZegEAgD0SUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEBwuvbAZVluxxhPxhh3a88GAFjZzRjj45zz2UMPrh5RY4wny8np9eHy6voIs3kEF2dbb0B1OPNyec/Offd26+L889YrEN2+/TA+3X9JZ48RUXeHy6vr569/O8JoHsOrn7fegOqXpz9uvQL/w8sbP8R79erFu61XIPr19z/G3/++vytnPbYCAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEAgogAAAhEFABCIKACAQEQBAAQiCgAgEFEAAIGIAgAIRBQAQCCiAAACEQUAEIgoAIBARAEABCIKACBY5pzrDlyW98vJ6fXh8mrVuTyei7OtN6A6nHku2rNz373dujj/vPUKRLdvP4xP91/+m3P+9NCzx4io+zHGD2OMv1YdzGN5+e3zn023oHJ/++Xu9s397dfNGOPjnPPZQw+err/LeDPGGHPO10eYzZEty/LnGO5vr9zffrm7fXN/3yfv/gEAAhEFABCIKACAQEQBAAQiCgAgWP0vDgAAvgfeRAEABCIKACAQUQAAgYgCAAhEFABAIKIAAAIRBQAQiCgAgEBEAQAEIgoAIBBRAACBiAIACEQUAEDwFeA+Thr0RrGzAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "execution_count": 10, "metadata": { "image/png": { "height": 72, "width": 296 }, "needs_background": "light" }, "output_type": "execute_result" } ], "source": [ "# cividis\n", "print(cividis)\n", "sns.palplot(cividis)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Each sequence ranges from cooler colors to warmer colors, making the colors appropriate for use on a heatmap. In Mapbox Studio, select the __Color__ option to style your heatmap and click on the color that represents the value 0.1 (\"royalblue\"). You should see an interactive color picker appear with options to modify the color values directly. Choose one of the five color palettes I've printed and copy the first six-digit hexadecimal code in the printed list (you don't need the number sign as it is already provided) to the corresponding box with the number sign to the lower right of the interactive color picker. You should see that color change on the map to your selected color. \n", "\n", "One-by-one, modify the five map colors using the hexadecimal codes from your selected color palette. For example, this is what your map might look like using `inferno`: \n", "\n", "\n", "\n", "If you'd like, you can also modify the \"stops\" that correspond to each color value to tune the color blending accordingly.\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "3. While the color scheme is now more appropriate, it is difficult to understand _where_ the concentrations of violations are because your heatmap is fully opaque. Choose the __Opacity__ option and lower the value to make your heatmap layer semi-transparent. You might also consider modifying the __Weight__ and __Intensity__ options to make your heatmap less intense. Experiment with these different options until you achieve a representation that you like. \n", "\n", "4. Finally, integrate your heatmap's relationship better with the other map layers by modifying its positioning. You may notice on the left-hand side of the screen that each element of the map - from map labels to roadways to water features - is represented in hierarchical order, with your heatmap layer sitting at the very top. Click your intoxication layer in the layer list and drag it beneath all of the label layers (the last one listed is \"road-label\") and note how the visual hierarchy of your map changes, with labels above your heatmap." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Sharing your map\n", "\n", "Now that you've made modifications to your map visualization, it is ready to share! Click the __Publish__ button in the top right corner of your screen to publish your map. Once published, click __Continue editing__. There are a couple different ways that you can share your map. The __Print__ button allows you to export your map as a static image. The __Share__ button gives you a series of options for sharing your map either as a standalone interactive map or as an embedded element in a mobile or web application. Click __Share__, and note the URL which you can copy in the __Share style__ section. Click the \"Make Public\" button to make your style share-able, then try copying this URL and pasting in a web browser; you'll see your map appear full-screen. \n", "\n", "Below this section, note the __Developer resources__. This gives you some resources to embed your map in a website or a mobile application. To complete this assignment, you'll get some small experience embedding the Mapbox map that you've designed in a stand-alone web page using Mapbox GL, Mapbox's web development library.\n", "\n", "If you haven't already, download the HTML file from TCU Online named \"example_map.html\". Open the HTML file in a text editor, not a web browser. To do this, either right-click the downloaded file and choose an option to open the file in a text editor (e.g. Notepad on Windows or TextEdit on a Mac), or open the text editor first, choose __Open__, and navigate to your HTML file. \n", "\n", "You'll see some HTML code that I've copied from [the Mapbox \"Display a map\" tutorial](https://docs.mapbox.com/mapbox-gl-js/example/simple-map/). You don't need to understand everything that is going on here, but I do want to get you some practice modifying it. The HTML file is a text file that can be interpreted by web browsers and rendered as a website. It can be downloaded and hosted on your personal website, for example. \n", "\n", "Look for the section inside the `` tags that appears as below:\n", "\n", "```html\n", "\n", "\n", "```\n", "\n", "Copy the \"Access token\" from your Share dialog in Mapbox Studio (it starts with \"pk.\") and replace the existing access token in the HTML code with your own. Next, do the same for the style URL. Save the map file, then try opening it in a web browser (navigate to the file through your computer's filesystem, then double-click the file to launch it). If it does not appear immediately, it is because the styles take a few moments to publish after you've first published them; you can add the text `/draft` directly after your style URL to view it right away (I have this example saved for illustration).\n", "\n", "## For submission\n", "\n", "To get credit for this assignment, modify the `example_map.html` file as instructed above with your Mapbox access token and style URL and upload your map file to the submission console in TCU Online. This will allow me to view your map!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [] } ], "metadata": { "interpreter": { "hash": "2b9421c38bd9785733c8ab589f124ba12ef5207025179e9d09f8a045acc4fc72" }, "kernelspec": { "display_name": "Python 3.9.5 64-bit ('python39': conda)", "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.9.5" } }, "nbformat": 4, "nbformat_minor": 4 }