trailhead

Get the GeoJSON File

Next we need a GeoJSON file with zip codes matching (or at least overlapping with) the ones in the CSV file. There’s one all ready for you, which you can download from here.

Reformat the GeoJSON

GeoJSON comes to us in the standard format:

{
	"type": "FeatureCollection",
	"features": [{
		"type": "Feature",
		"properties": {
			"kind": "ZIP Code Tabulation Area (2012)",
			"external_id": "90001",
			"name": "90001",
			"slug": "90001-zip-code-tabulation-area-2012",
			"set": "/1.0/boundary-set/zip-code-tabulation-areas-2012/",
			"metadata": {
				"AWATER10": 0,
				"CLASSFP10": "B5",
				"ALAND10": 9071359,
				"INTPTLAT10": "+33.9740268",
				"FUNCSTAT10": "S",
				"ZCTA5CE10": "90001",
				"MTFCC10": "G6350",
				"GEOID10": "90001",
				"INTPTLON10": "-118.2495088"
			},
			"resource_uri": "/1.0/boundary/90001-zip-code-tabulation-area-2012/"
		},
		"geometry": {
			"type": "MultiPolygon",
			"coordinates": [
				[
					[
						[-118.265151, 33.970249],
						[-118.265166, 33.974735],
						[-118.262969, 33.974746],
						[-118.262981, 33.981836],
						[-118.265174, 33.981828],
						[-118.265185, 33.989227],
						[-118.256436, 33.989317],
						[-118.256436, 33.989498],
						[-118.241159, 33.989422],
						[-118.241126, 33.988174],
						[-118.240505, 33.988158],
						[-118.240502, 33.98867],
						[-118.23899, 33.988664],
						[-118.239021, 33.989403],
						[-118.237918, 33.989393],
						[-118.235685, 33.979486],
						[-118.235352, 33.979534],
						[-118.235105, 33.978705],
						[-118.234324, 33.974732],
						[-118.234685, 33.974731],
						[-118.234432, 33.972967],
						[-118.233915, 33.970674],
						[-118.233561, 33.970731],
						[-118.232835, 33.967469],
						[-118.232995, 33.967467],
						[-118.232405, 33.965314],
						[-118.231371, 33.963268],
						[-118.230013, 33.961768],
						[-118.231885, 33.961565],
						[-118.231599, 33.960146],
						[-118.237366, 33.960152],
						[-118.23737, 33.958521],
						[-118.237943, 33.958518],
						[-118.237949, 33.96015],
						[-118.24499, 33.960148],
						[-118.244994, 33.959648],
						[-118.246648, 33.959637],
						[-118.246653, 33.959177],
						[-118.247237, 33.959175],
						[-118.247225, 33.9597],
						[-118.253962, 33.959701],
						[-118.253959, 33.960162],
						[-118.258573, 33.96016],
						[-118.258575, 33.959577],
						[-118.260754, 33.959772],
						[-118.260753, 33.960149],
						[-118.265118, 33.96013],
						[-118.265139, 33.966482],
						[-118.264629, 33.966483],
						[-118.264607, 33.967438],
						[-118.265142, 33.967395],
						[-118.265151, 33.970249]
					]
				]
			]
		}
	}, ...]
}

Standard GeoJSON works well in most applications, but it’s problematic for custom maps in Analytics. The problem isn’t in displaying the map; it occurs when you try to display data using the map chart. That’s because Analytics looks for an ID at the same level as the "type": "Feature" node that matches an ID in the data. That’s how it knows to match a row from the CSV file to a particular zip-code area on the map. In fact, that ID property has to be named "id"!

In this example, the obvious ID to use is the zip code value itself. The fix is to move the key up one level, or just “flatten” the GeoJSON by moving everything under properties up one level. Get ready to use your coding skills!

  1. For the Los Angeles zip codes, create a script or use a fancy regular-expressions formula to move external_id up one level so it’s a child of features.
  2. Be sure to rename the new key-value node "id".
    The value of each "id" will be a zip code, to match the zip codes in your dataset's Zipcode column.
  3. If your script output a file with a new name, note the name of the file and its location. You need them when you upload the GeoJSON to Analytics.

For example, here’s a quick-and-dirty Python script that creates the id node at the same level as type:

                                #!/usr/bin/python
                                
                                import json
                                
                                f = open('Downloads/test_la_zip_code_areas_2012.json', 'r')
                                
                                json_contents = json.loads(f.read())
                                
                                features = json_contents["features"]
                                
                                for i in features:
                                    i["id"] = i["properties"]["external_id"]
                                
                                # If shrinking the size of the file is important, 
                                # the properties node could be deleted afterwards:
                                # del i["properties"]
                                
                                out_file = open("out_la_zip_code_areas_2012.json", "w")
                                out_file.write(json.dumps(features))
                                
                                # out_file will not be sorted, which shouldn't affect anything,
                                # but to have it be sorted, use sort_keys=True in json.dumps
                                
                                out_file.close()
Note

Note

The quick-and-dirty script shown above actually stripped the wrapper around the feature objects, so if you use it, restore the following:

{    
                			"type": "FeatureCollection",
                			"features": {[
                			"comment" : "stuff that was output by the script goes here"
                			]}
                			}

Now the GeoJSON looks something like this:

{
	"type": "FeatureCollection",
	"features": [{
		"type": "Feature",
		"properties": {
			"kind": "ZIP Code Tabulation Area (2012)",
			"external_id": "90001",
            ...
			},
			"resource_uri": "/1.0/boundary/90001-zip-code-tabulation-area-2012/"
		},
		"id": "90001",
		"geometry": {
			"type": "MultiPolygon",
			"coordinates": [
				[
					[
						[-118.265151, 33.970249],
                        ...
					]
				]
			]
		}
	}, ...]
}

Every id has the value of the actual zip code in the feature object that it’s a part of. Don't try to use this GeoJSON snippet, it's just a small part of the output you'll get!

Upload the GeoJSON and Create the Map

In Analytics, you can use the same GeoJSON to create multiple maps, each with a different zoom factor or focus area. But first, upload the GeoJSON to Analytics. Feel free to use our sample GeoJSON file instead of your own. Just right-click this link and save the linked file as a file on your local machine.

  1. Log in to your Salesforce DE org, and navigate to the URL formed by appending /analytics/wave/web/custommap.apexp to your org’s base URL. For example, if your org’s base URL is https://na30.salesforce.com, go to https://na30.salesforce.com/analytics/wave/web/custommap.apexp.
  2. Click New.

    The insertion window for a new custom map appears. It has two panels, one for the GeoJSON and one for the map itself.

  3. Fill in GeoJSON Label and GeoJSON Name with la_zip_codes.

    The GeoJSON name and label appear in the custom-map administration screens.

  4. Select the zip-codes GeoJSON file you reformatted for GeoJSON Definition.
  5. Click Insert and look for a confirmation message in the Results section of the insertion window.
    Now you can create the map.
    custom map geojson upload screen
  6. Fill in Map Label and Map Name with L.A. Zipcodes. The map name and label appear in Analytics.
  7. Select Equirectangular from the Projection menu.

    Equirectangular is appropriate for simple geometric shapes such as zip-code areas.

  8. Select the GeoJSON definition you created, la_zip_codes, from the GeoJSON menu.
  9. Click Insert Map and look for a confirmation message in the Results section of the insertion window.
    custom map insert map screen

Once you create the map, you can choose it from the list of maps available in Analytics for the map chart. It appears in Analytics like this:

custom map los angeles zip codes with no data

Congratulations! You’ve created your first custom map. And isn’t it a beauty!

Note

Note

If there’s something wrong with the GeoJSON file that you uploaded, an error message appears (something like “Invalid GeoJSON”) instead of the map. Usually that means something went wrong with the reformatting.

Explore the Data

When you created the Los Angeles zip-code dataset, you set the Zipcode column’s data type to dimension. This makes it possible to group on zip code when you explore the data.

Now explore the zip-code data in a lens and view it on the map:

  1. From the Analytics home page, click Browse All.
  2. On the browse page, locate the zip-code dataset you created, then click it to explore it in a lens. initial lens view of los angeles zip-code tax data
  3. In the lens, click the Count of Rows measure, then Sum, then TotalWages to change the measure to Sum of TotalWages.
    Make sure to click the name of the measure you're changing, Count of Rows, in the Measures panel.
  4. Click the Group by plus button, then Zipcode to group by Zipcode. los angeles zip-code tax data sum of total wages grouped by zip code
  5. Click button to clip lens to builder to open the step naming dialog.
  6. Leave the Display Label as is, and click Clip to Designer to clip the lens to the dashboard designer.
  7. In the dashboard builder, drag the new step onto the canvas. Adjust the size of the widget as necessary to be able to view the bar chart that appears.
  8. From the Chart Type menu, select Map for the chart type, then close the menu.
  9. Open the Map panel and select Custom: L. A. Zipcodes from the Map Type menu.
    An unimpressive map appears with several colored zip-code areas where Los Angeles is found (those flyspecks approximately in the central part of the visible coast). los angeles zip-code map with tax data
  10. Save the dashboard, naming it Los Angeles Tax Data by Zip Code.

The problem with this map is that it includes zip-code areas for all of Southern California, which means the Los Angeles area is much too small to be useful. We can fix that by creating bounding boxes. We do that next.

Time Estimate
Topics
retargeting