Monday, September 17, 2012

My Esri Internship Experience


Have you ever used a location related phone application? Chances are the answer is yes. Perhaps you have used your smartphone to “drop a pin” so you could find your car. Maybe you have used a food truck tracker or done a fastest route search. It is common practice to “check-in” to a location on your phone with services such as Facebook and Foursquare. So what is the common denominator? Every time you use a location app, there is some sort of map in the background! 

Have you ever wondered where that map came from or how it was made? This summer I got the chance to help build one of those “background” maps. In the world of GIS, they are known as “basemaps”.  

In this post I will talk about my internship experience at Esri, the world’s leading software developer for location based technology. I will also talk about some of the invaluable lessons I learned about the future of geospatial intelligence (aka GIS). At the end of this post I make suggestions to college GIS programs (specifically UCLA) on how to leverage web/mobile technology to promote the major.


When Esri’s new desktop software, ArcMap 10, rolled out last year, basemaps were my favorite addition. I would wonder how the basemaps were created and where they came from, they seemed to just appear! This summer I got the answer to my questions when I received the chance to intern at Esri and help develop the World Topographic Map, Esri’s flagship basemap. Click here to view the Esri World Topo map online.


Esri currently offers 12 basemaps

 
The division of Esri that creates some of these maps is called the Community Maps Program and they have been full steam at work for the last 3 years to develop the world’s most comprehensive topographic map ever created. The magnitude of this project is larger than has ever been attempted; the goal is to create a map that integrates authoritative GIS data from different communities into one enormous map. You can think of the map as a quilt that is made up of patches; communities that own and maintain their GIS of features such as landscaped areas, streets, buildings, trees and waterbodies can contribute their data and Esri will integrate their patches into the quilt. So far about 620 communities have contributed their data to the map. The main benefit to the contributor for doing this is that Esri will host the basemap in the cloud so it is easily accessible to anyone who needs it. Many contributors have created mobile and web applications that use the map for things such as public works data collection, community maintenance requests and crime reporting. 

Credit: Esri Community Maps Program




Community Maps Template





During my internship at Esri, I worked on an intern team of 4 and we were each tasked with digitizing our college campuses to integrate into the World Topo basemap. I digitized the University of California, Los Angeles (UCLA) and the other interns digitized Cal State University Long Beach (CSULB), Arizona State University (ASU) and Cal State University San Bernardino (CSUSB). This exercise was more about learning the process of building a basemap and developing digitizing best practices to share with contributors. Usually a campus would contribute their own data but none of our schools are participants. Currently there are 81 campuses that have contributed their data to Esri’s Community Maps Program. Click on this link to see examples of campuses in the World Topographic map. If any of our schools decide to contribute their data, Esri will swap out what the interns created with the authoritative data owned by the campuses.





We spent about 3 weeks digitizing our campuses from scratch and it was the first time I had ever worked in a template. We digitized at four scales: 1:9K, 1:4.5K, 1:2K and 1:1K (farther out to closer in). It took me a while to wrap my head around how to do this. The idea is that the farther out you are on the map, fewer details appear and as you zoom in closer more details show up. The main way to control what shows up at different scales is through something called “definition queries”. Basically by using Structured Query Language (SQL), you can form statements (aka definition queries) such as: [“Area” > 900] and this could mean something like: only display the building labels at the 1:2K scale if the area is greater than 900 meters squared.















I also gained experience with a geodatabase called the “Local Government Information Model” (LGIM). The Local Gov’t model is a standardized way of organizing a municipality’s GIS data and it is also the required format for submitting one’s data to the Community Maps Program. The model can be downloaded from here. I had worked within an information model once before when I helped the City of Los Angeles find a new park location; I was able to apply that knowledge when I started working with the LGIM. 


This is the full Local Government Information Model. Municipalities use this to organize their GIS. The Community Maps Program only utilizes a small subset from this model such as streets, buildings and landscape




















In the campus digitizing process I came up with some pretty impressive statistics for UCLA. Did you know that if you walked on every single sidewalk at UCLA, you would walk 27 miles?! That’s more than a marathon! Can you guess how many trees there are at UCLA? Well I can't be certain because I did not digitize trees at 1:1, but I digitized roughly 13,500! Yes ladies and gentlemen, that means I clicked my mouse 13,500 times! I did this in 6 hours; that’s cyber tree planting madness at 37 clicks a minute folks! I am proud to say that over 120 hours of digitizing later, I am a master!


UCLA by numbers: 

·         419 acres
·         174 buildings
·         15 parking structures
·         18 landmarks
·         40,675 student population
·         27 miles of sidewalk
·         ~13,500 trees


My internship at Esri also exposed me to a critical part of GIS that I had never encountered before – Quality Control (QC). Performing quality control checks and double checks is common practice at Esri. I learned how to use Esri’s Data Reviewer extension to perform visual and automated QC checks. I also cross referenced the map I created with UCLA’s official map for accuracy. 

Just so you understand what maps are currently out there, here is what UCLA looks like in Satellite Imagery, Google, Bing, Esri’s World Streets, UCLA’s interactive map and Esri’s World Topographic map (before my addition):  


Esri Satellite Imagery (2010)


Google 

 Esri Streets Map

Bing

Esri World Topographic Map


As you can tell the Bing, Google and Esri maps are relatively empty. The only map that has a high level of detail is UCLA’s interactive map (the authoritative data steward) so it takes 1st place. The google map takes 2nd place because it does a good job of labeling the campus and it has some general symbolization for grass, buildings, pavement and sports fields. The Esri World Streets map comes in 3rd place because there are some digitized features such as the track and field stadium; however the labeling is sparse and the digitizing quality is poor. The bing map come in 4rd place because it has buildings, a few building labels and sidewalks. The Esri World Topographic map comes in last place (for UCLA's campus) because it only has buildings, contours and NDVI generated vegetation. My goal was to change that and put the Esri World Topo map in 1st! 

This is what I came up with: 



Looks pretty good, right?! The image above shows the campus at the 1:4,500 scale (4.5K). 

A few weeks after we finished digitizing our college campuses, the Community Maps Program came out with a brand new cartographic template. The interns were asked to change our maps over to the new template. The colors in the new template are much more toned down. Since the basemap is intended to be a reference map, the subtle “in-the-background” look is more suitable. This way it is easier for users to overlay operational layers (things that change) on top of the basemap (ie updated campus shuttle routes, construction zones, building hazards, etc).

Old cartography
New cartography

Old cartography (zoomed in on UCLA Sunset recreation)
New cartography (zoomed in on UCLA Sunset recreation)



This is what Esri’s World Topographic map will look like this when my digitized UCLA campus is integrated into the basemap:



Esri’s World Topographic map (currently)

Esri’s World Topographic map (after my addition)



 The following images will show the final campus map at the different scales (1:9000 to 1:1000) and special areas of interest.


1:9000

1:4,500

1:2,000

1:1,000

1,1000








 
Suggestion to UCLA (and other college campuses):

Since UCLA is now going to be part of the Esri basemap, it would be awesome if some GIS students developed a campus application that allowed smartphone users to geotag special events, sports games, crime incidents etc! Other campuses can do this too, they just need to digitize their campus and submit it to Esri. Click on this link to get info on how to participate in the Community Maps Program.

If you want to promote the GIS program and show off how awesome GIS is …then this is what you can do. Collaborate with Computer Science and GIS students to develop a mobile app that on its most basic level helps students find places. Then incorporate a community editing aspect that allows the student body to participate. 

QR code
Get the Den Sports Club involved and have them update all sports events. Get student associations such as ASUCLA, SAA, SEC and USAC involved with campus events updates. Have bruin alerts be geotagged! Get social media involved (youtube, twitter, facebook) – did a fantastic dancing flash mob wedding proposal just occur in the middle of Bruin Plaza? Tag the video right onto the map! Sky is the limit, whatever other applications you can think of. 

Have someone present the application during freshman orientation to each group that comes through and make it downloadable straight from www.UCLA.edu. Put QR codes around campus that link to the app download. Have students blog about the app, have the Daily Bruin cover it, do a press release to local TV stations. Say that people in the GIS major did it! This could be a big class project for a Web/mobile GIS class. Do this and people will be flocking to Geography/GIS major, it will grow faster than you ever imagined. People will figure out that GIS is a valuable major and YES you can get a job! Web/mobile GIS is the wave of the future, hop on board people!

Friday, July 27, 2012

Custom Python Script - Batch Raster Extractor

Introduction 


This code was created during a Programming and Development for GIS course at UCLA during Winter 2012. The purpose of the code is intended for research conducted by Dr. Thomas Gillespie of the UCLA Geography Department, however the code can be used for a variety of applications.

Dr. Gillespie's research involves identifying global biodiversity hotspots that have seen significant landcover change. The data set being used is called the GLOBCOVER project and it is created by the European Space Agency (ESA). The data is a satellite imagery raster that has been classified into landcover types. A new data set is created every few years and Gillespie's research goal is to compare eco-regions, countries and protected areas over time to look for forest degradation.

To help solve this research question, this code produces statistics of landcover area (km2) and percentage land cover (%) for polygons (ie eco-regions, countries and protected areas). This is accomplished by using the polygons to extract pixel data from the GLOBCOVER raster. In order to do a temporal comparison, a separate code would be required to draw comparison statistics.




Technical Code Description:
The Batch Raster Extractor is meant to provide a standard and repeatable way to extract raster data using the polygons of a vector file. The script operates in four main steps. First, the user inputs the vector file and raster file of interest. Second, a split by attribute tool is used to export each polygon into a separate shapefile. Third, each polygon is masked on top of the raster and used to extract a subset of the raster. Fourth, statistics are calculated for each raster subset, Area and Percentage fields are appended to the attribute tables of each subset.

Code Requirements:
To use this code, the user must have Python 2.6 for ArcGIS 10 (or above) installed. A custom python script called "Split Layer by Attributes" is used in this code, it must be downloaded for this code to work from this link. User must have licensing for ArcGIS Spatial Analyst Extension.

Code Usage Guide:
  1. Copy and past code below into Python IDLE window and save as a .py. 
  2. Change / modify the ten lines in the code that have a comment on the right hand side in green (indicated by ' ### '  )
  3. Save  [ CTRL + S ]
  4. Run [ F5 ]
Trouble Shooting
  1. If code returns a 'NoneType' error, close all files (including ArcMap, IDLE and shell) and re-run code. (This error is due to the code's use of the custom tool "Split Layer By Attributes"
  2. If code crashes while running, it is possible that polygons exist in the vector file that do not have corresponding raster data to extract. To fix this, manually remove those polygons in ArcMap.

Code broken down into pictures:


Step 1: 

Specify two inputs 

1. Vector Layer
  • example = shapefile of all countries in world


















2. Raster Layer
  • example = GlobCover , European Space Agency (ESA) 




















Step 2: 

Split apart shapes within vector file and save each as a separate shapefile (.shp)




 

Step 3: 

Use geometry of each shape to "cookie cutter" raster and save each subset as a raster file



Step 4: 

Calculate pixel statistics 
  •  will append attribute table with Area (Km2) and Percentage fields (this screen shot is from an earlier iteration of the code when the percentage field was not populating correctly, this bug has since been fixed)



PYTHON CODE


'''BatchRasterExtractor.py

Author:
  Kelsey Kaszas
  Dept of Geography and Environmental Studies
  University of California, Los Angeles, USA
  kelsey.kaszas@gmail.com
  Special Thanks to Jida Wang 

Date created April 9 2012
Modified     July 27 2012

Purpose:
  Converts each shape in a feature class into a separate shapefile.
  Uses individual shapefiles to extract raster data by mask.
  Appends extracted raster files with "Value", "Area", and "Percent" fields. 
  Final output is a folder with masked raster subsets. 

Code Requirements:
  This code requires the user to have Python 2.6 for ArcGIS 10 (or above) installed on computer
  This code uses a custom python script called "Split Layer By Attributes" that can be downloaded from: http://arcscripts.esri.com/details.asp?dbid=14127
  This code requires ArcGIS Spatial Analyst Extension
  
Code Usage Guide [ IMPORTANT ] :
  1. change the ten places in code that have a comment on the right hand side (indicated by ' ### ') 
  2. save code [ CTRL + S ]
  3. run code [ F5 ]
  
Troubleshooting:
  1. If code returns a 'NoneType' error, close all files and re-run code
     (this error is due to the code's use of the custom tool "SplitLayerByAttributes")
  2. If code crashes while running, it is possible that polygons exist in the vector file that do not
     have corresponding raster data to extract. To fix this, manually remove those polygons using ArcMap
     
   
'''
#--------------------------------------------------------------------

#import system module 
import arcpy, os
from arcpy import env
from arcpy.sa import * 

#enable overwrite 
arcpy.env.overwriteOutput = True

#define filepath
filepath = r"D:\My Documents\RASTER_EXTRACTER"                                      ### change path to workspace folder
arcpy.ImportToolbox(r"D:\My Documents\SplitLayerByAttributes.tbx")                  ### change path to location of "Split Layer By Attributes" toolbox .tbx
symbologyLayer = r"D:\My Documents\GlobCover_Legend.lyr"                            ### comment out or delete this line if there is NO symbology .lyr file 


#set parameters 
#vector = arcpy.GetParameterAsText(0)
vector = r"D:\My Documents\vector.shp"                                              ### change path to vector dataset 


#raster = arcpy.GetParameterAsText(1)
raster = r"D:\My Documents\raster.tif"                                              ### change path to raster dataset

#out_vector = arcpy.GetParameterAsText(2)
out_vector = r"D:\My Documents\vector_output"                                       ### change path and change \vector_output to name of folder that will contain individual shapefiles
out_vector = str(out_vector)
os.makedirs(out_vector)

#out_raster = arcpy.GetParameterAsText(3)
out_raster = r"D:\My Documents\raster_output"                                       ### change path and change \raster_output to name of folder that will contain subset raster files                                                                                 
out_raster = str(out_raster)
os.makedirs(out_raster)

#set workspace environment 
arcpy.env.workspace = out_vector

#input pixel size of raster
z = ???                                                                             ### change ??? to pixel size of raster (units in meters) (example: z = 300)                                                           

#[SPLIT]
#_________________________________________________________________________

print("running split...")

#print(out_vector)

name_vector = '???'                                                                 ### choose naming convention: change ??? to the field name from original shapefile that output vector naming convention will be based on
arcpy.SplitLayerByAttributes(vector, name,"_",out_vector)                                                                          
print("split completed")

#[MASK]
#________________________________________________________________________

print("adding symbology layer to original raster file")
arcpy.ApplySymbologyFromLayer_management (raster, symbologyLayer)                   ### Comment out or delete this line of code if there is NO symbology .lyr file


#Check out the ArcGIS Spatial Analyst extension license
arcpy.CheckOutExtension("Spatial")


print("running mask of shapefile output")
for file1 in os.listdir(out_vector):    
    if file1.endswith(".shp"):
        
        #cursor out name of individual vector outputs for raster file naming convention 
        name = arcpy.SearchCursor(file1)
        for name_1 in name:
            raster_name = name_1.name_vector
            break       

        # Execute ExtractByMask
        outExtractByMask = ExtractByMask (raster, file1)  

        # Save the output
        outExtractByMask.save(out_raster + "/" + str(raster_name))



        print("performing statistics on raster. step 1...get a total pixel count from new raster subset")
        count_list = []
        value_list = []
        searched_rows = arcpy.SearchCursor(outExtractByMask)
        total_count = 0
        for row in searched_rows:
            value_list.append(row.VALUE)
            count_list.append(row.COUNT)
            total_count += row.COUNT

        print(str(total_count))

        
        print("step 2...creating tmp.dbf to serve as intermediary")
        tmpTABLE = "tmp.dbf"
        if os.path.exists(tmpTABLE):                                          
            os.remove(tmpTABLE)                                               
        
        arcpy.CreateTable_management(out_vector, tmpTABLE)

        print("step 3... add fields to tmp")
        #ADD FIELDS to tmp table
        arcpy.AddField_management(tmpTABLE, "VALUE", "LONG")
        arcpy.AddField_management(tmpTABLE, "area", "DOUBLE")
        arcpy.AddField_management(tmpTABLE, "percent", "DOUBLE") 
        print("table created")
        
        #UPDATE the tmp table with calculation in added fields
        new_row = arcpy.InsertCursor(tmpTABLE)
        searched_rows = arcpy.SearchCursor(outExtractByMask)
        index = 0
        print("step 4...update the tmp table with calculation in added fields")
        for searched_row in searched_rows:
    
            #print index
            row = new_row.newRow()
            row.VALUE = value_list[index]
            row.area = z*z*1.0*count_list[index]/1000000                                                                                  
            row.percent = count_list[index]*100.0/total_count
            index = index+1
            new_row.insertRow(row)
    
        del row
        del new_row
        del searched_row
        del searched_rows

        print("step 5 ...join the tmp table to attribute table of the newly subset raster file")         

        #join tables to the attribute table of the raster file
        arcpy.MakeRasterLayer_management (outExtractByMask,  "layerName")     
    
        # Join the feature layer to a table
        arcpy.JoinField_management("layerName", "VALUE", tmpTABLE, "VALUE")       
             
        if os.path.exists(tmpTABLE):                                          
            os.remove(tmpTABLE)


print("extract by mask completed")
code snippet creator: http://hilite.me/

Sunday, May 20, 2012

Redbox DVD Kiosks Network Analysis




 Redbox is a freestanding DVD and Blu-Ray Kiosk that can be found in various retail and grocery stores. My goal is to determine if there is a connection between race and redbox service areas.


The goal of this class assignment was to learn how to use the Network Analyst extension in ESRI ArcGIS. A Network Analysis is used on a streets layer to determine service zones and shortest routes. The most important thing about how a network analysis works is that it uses Manhattan distance (Fig. 2) to measure instead of Eucledian distance (Fig. 1). The difference is that a Eucledian distance is linear, for instance a point with a 1 mile radius circle around it. Manhattan distance is better for a network analysis because it is based on roads, a service area should be based on accessibility. 





 Fig1. Eucledian Distance                    Fig2. Manhattan Distance 

My goal was to see if there is a connection between race and redbox service areas. In order to do this I used Census data from 2000 of Los Angeles County. I used the Census's “Tracts” layer which includes racial and population data. I then loaded the Redbox point shapefile into network analyst by following these steps: 

1. Open Network Analyst toolbar and from “Network Analyst” dropdown and select “New Service Area” 
2. On same toolbar click “Show/Hide Network Analyst Window” icon 
3. Rt. click “Facilities(0)” and select “Load Locations…” 
4. Set “Load From:” input to Redbox layer 
5. In Table of Contents go to properties of Service Area 
6. Go to “Analysis Settings” tab and change Impendence to “Length (miles)” and Default Breaks to “1”. 
7. Solve! 

This will generate 1 mile service zones for each Redbox unit. I then performed a spatial join with the tracts layer in order to determine the demographic breakdown of Redbox service zones. I summed up the number of Blacks, Whites, Hispanics, Asians and Other in Redbox service zones and for all of Los Angeles. I then calculated the percentages of each race in the Redbox service zones and subtracted them from the baseline demographic breakdown of Los Angeles County. The results show that Redbox units are 5% more likely to be found in areas dominated by White people and 3% less likely to be found in areas dominated by Hispanic people. In conclusion, there is not a significant difference in the demographic breakdown of Redbox service zones and the demographic breakdown of Los Angeles County. 





I also created this second map which shows a close-up of the Redbox service zones in the South Bay (Manhattan Beach, Hermosa Beach and Redondo Beach. This map is meant to show what the service zones looks like at a smaller scale.


Source:

 Redbox data: http://geocommons.com/overlays/239760 (Dataset derived by merging the features of 'Total IRS Gross Collections (in thousands), USA by State, FY2008' into 'Redbox Kiosk Locations')

The Redbox location data can be downloaded as a KML (Google Earth), shapefile or spreadsheet (CSV).





Friday, April 27, 2012

Proposition 8 Maps

In 2008, Proposition 8 changed the California state constitution to prohibit same-sex marriage but did you know that more in-state donations were made by those opposed to the ban? Prop 8 still passed by over a half million votes. These maps were created to draw a comparison between donations and votes to "no on 8" (oppose ban) and to "yes on 8" (support ban). The data comes from public financial records submitted to the California Secretary of State. 

The first map in the series shows the spatial distribution of donations for "no on 8" (oppose ban) in California by zipcode. The heights are based on total dollar amount and darker colors indicate a higher number of contributors. The subset maps compare donations in Northern and Southern California. Seven out of the top ten counties with the highest amount of pro-gay marriage donations came from Northern California. The county with the highest total donation and largest number of contributors to "no on 8" was Los Angeles. Interestingly, Los Angeles County voted for "yes on 8" (support ban) by a mere 0.20%.



The second map in the series shows the spatial distribution of donations for "yes on 8" (support ban) in California by zipcode. The heights are based on total dollar amount and darker colors indicate a higher number of contributors. The subset maps compare donations in Northern and Southern California. The top five counties with the highest amount of donations to “yes on 8” all came from Southern California. The county with the highest total donations to “yes on 8” was Orange County. In addition to being the county with the largest number of contributors to "no on 8" (oppose ban), Los Angeles was also the county with the largest number of contributors to “yes on 8”. 



The following maps show a comparison between donations to "no on 8" (oppose ban) and to "yes on 8" (support ban) in San Diego, Orange, Los Angeles, San Francisco, Alameda and Sacramento Counties. The heights are based on total dollar amount and darker colors indicate a higher number of contributors. Since there are donations to both no and yes in most zipcodes, I have included inset maps for each side. The larger county maps are a combination of donations to both no and yes; whether or not the region is colored blue or red depends on which side donated more. I have also included graphs that shows how the county voted and which side spent more money.

The donation and voting data shows San Diego County as predominantly against marriage equality. The largest amount of money donated to "no on 8" (oppose ban) came from Mission Hills followed by the 92104 and 92116 zipcodes in City of San Diego. Interestingly, the second largest sum of money donated to "yes on 8" (support ban) came from 92120 in City of San Diego, a zipcode adjacent to 92104 and 92116. The largest amount of money donated to "yes on 8" came from La Jolla from a small amount of contributors. Other areas with high contributions to "yes on 8" include El Cajon, Poway, Fallbrook, Carlsbad, Encinitas and Rancho Penasquitos. 


The donation and voting data shows Orange County is predominantly against marriage equality as well. Even the most liberal area of Orange County, Laguna Beach, received over three times as much money to "yes on 8" (support ban) as to "no on 8" (oppose ban). The largest amount of money donated to "yes on 8" came from Irvine and the highest number of contributors to "yes on 8" came from Fountain Valley, Laguna Niguel, Rancho Santa Margarita and Yorba Linda. The majority of Orange County donated to and voted for “yes on 8”.


Los Angeles County donated over 11 million dollars to "no on 8" (oppose ban), twice as much as was donated to "yes on 8" (support ban), but “yes on 8” prevailed by just 2385 votes. The largest sums of money donated to "no on 8" were from Beverly Hills, West Hollywood and Hollywood. The largest number of contributors to "no on 8" came from Long Beach, Santa Monica, West Hollywood, Hollywood and Beverly Hills. The largest sums of money donated to “yes on 8” came from La Canada & La Crescenta, Palos Verdes and La Verne. The largest number of contributors to “yes on 8” came from the City of Long Beach.


The donation and voting data shows that San Francisco County is predominantly in favor of marriage equality. Nearly 7 million dollars was donated to "no on 8" (oppose ban), five times as much money as was donated to "yes on 8" (support ban). "No on 8" voters outnumbered “yes on 8” voters 3 to 1. The largest amount of donation to "no on 8" came from the Financial District, Fisherman’s Wharf, The Castro District and Noe Valley. The largest number of contributors came from Mission District, Haight, Glen Park and Diamond Heights. In comparison, a marginal amount of money was donated to “yes on 8”.


Alameda County is also predominantly in favor of marriage equality based on the total donation and votes. The largest amount of money and number of contributors to "no on 8" (oppose ban) came from Berkeley and Oakland. The largest amount of money to "yes on 8" (support ban) came from Pleasanton and Dublin, while the largest number of contributors came from Livermore and Pleasanton.


The donation and voting data show that Sacramento County is predominantly against marriage equality. The largest amount of money donated to "no on 8" (oppose ban) came from Downtown Sacramento (location of the California State Capitol Building) and the 95841 zipcode in the City of Sacramento. The largest amount of contributors to "no on 8" came from Downtown Sacramento. The largest amount of money donated to "yes on 8" (support ban) came from Granite Bay and Folsom. The largest number of contributors to “yes on 8” came from Folsom, Elk Grove, Fair Oaks and Granite Bay. 


These maps are based on campaign finance reports submitted to the California Secretary of State. The raw data for these maps can be downloaded as a .CSV file from the LA Times Prop 8 Money Tracker. The voting data can be viewed on the California Secretary of State Prop 8 voting map.

Proposition 8 has since been ruled unconstitutional by the U.S. 9th Circuit Court of Appeals and is likely to be appealed to the U.S. Supreme Court in the next few years. There is currently a stay on the ruling by the 9th Circuit Court since supporters of prop 8 immediately petitioned for a rehearing. Gay marriage is still prohibited in the state of California. 

Comments or questions? If you don’t see it on the map and are interested in knowing how YOUR area donated, email me at kelsey.ck@ucla.edu