Challenge 1: Your first map of Mexico

Workshop on “Creating maps with Stata and thematic applications” by Ben Jann, Hermosillo, October 24–25, 2023

0. Install geoplot and its dependencies.

ssc install geoplot, replace
ssc install palettes, replace
ssc install colrspace, replace
ssc install moremata, replace
ssc install geo2xy, replace
ssc install fre, replace // not needed by geoplot, but used in my solution below

To view the documentation of command geoplot, type help geoplot. To view the documentation of command geoframe, type help geoframe.

1. Convenient light-weight shape files for Mexico are provided by Carlos Efrain at https://www.efrainmaps.es/english-version/free-downloads/mexico/. Download and unzip the following files: Mexico_States.rar, Mexico_Cities.rar, Mexico_Hydrography.rar (rivers), Mexico_Lakes.rar, and Mexico_Roads.rar. Convert the shape files to Stata format using geoframe convert (or spshape2dta).

I download the files into subfolder source and unzip them therein. I then use geoframe convert to generate Stata format datasets in the working directory.

. geoframe convert States using source/Mexico_States, replace
(translating Mexico_States from directory source/Mexico_States)

  (importing .shp file)
  (importing .dbf file)
  (creating _ID spatial-unit id)
  (creating _CX coordinate)
  (creating _CY coordinate)

  file States_shp.dta created
  file States.dta     created

  (type geoframe create States to load the data)

. geoframe convert Cities using source/Mexico_Cities, replace
(translating Mexico_Cities from directory source/Mexico_Cities)

  (importing .shp file)
  (importing .dbf file)
  (creating _ID spatial-unit id)
  (creating _CX coordinate)
  (creating _CY coordinate)

  file Cities_shp.dta created
  file Cities.dta     created

  (type geoframe create Cities to load the data)

. geoframe convert Rivers using source/Mexico_Hydrography, replace
(translating Mexico_Hydrography from directory source/Mexico_Hydrography)

  (importing .shp file)
  (importing .dbf file)
  (creating _ID spatial-unit id)
  (creating _CX coordinate)
  (creating _CY coordinate)

  file Rivers_shp.dta created
  file Rivers.dta     created

  (type geoframe create Rivers to load the data)

. geoframe convert Lakes using source/Mexico_Lakes, replace
(translating Mexico_Lakes from directory source/Mexico_Lakes)

  (importing .shp file)
  (importing .dbf file)
  (creating _ID spatial-unit id)
  (creating _CX coordinate)
  (creating _CY coordinate)

  file Lakes_shp.dta created
  file Lakes.dta     created

  (type geoframe create Lakes to load the data)

. geoframe convert Roads using source/Mexico_Roads, replace
(translating Mexico_Roads from directory source/Mexico_Roads)

  (importing .shp file)
  (importing .dbf file)
  (creating _ID spatial-unit id)
  (creating _CX coordinate)
  (creating _CY coordinate)

  file Roads_shp.dta created
  file Roads.dta     created

  (type geoframe create Roads to load the data)

2. Load the shape files using geoframe create.

The data on rivers and lakes I declare as feature type water.

. geoframe create States, replace
(reading shapes from States_shp.dta)
(all observations in frame States_shp matched)
(link to frame States_shp added)
(current frame now States)

            Frame name: States
            Frame type: unit
          Feature type: <none>
         Number of obs: 32
               Unit ID: _ID
           Coordinates: _CX _CY
                  Area: <none>
    Linked shape frame: States_shp

. geoframe create Cities, replace
(reading shapes from Cities_shp.dta)
(all observations in frame Cities_shp matched)
(link to frame Cities_shp added)
(current frame now Cities)

            Frame name: Cities
            Frame type: unit
          Feature type: <none>
         Number of obs: 36
               Unit ID: _ID
           Coordinates: _CX _CY
                  Area: <none>
    Linked shape frame: Cities_shp

. geoframe create Rivers, replace feature(water)
(reading shapes from Rivers_shp.dta)
(all observations in frame Rivers_shp matched)
(link to frame Rivers_shp added)
(current frame now Rivers)

            Frame name: Rivers
            Frame type: unit
          Feature type: water
         Number of obs: 30
               Unit ID: _ID
           Coordinates: _CX _CY
                  Area: <none>
    Linked shape frame: Rivers_shp

. geoframe create Lakes, replace feature(water)
(reading shapes from Lakes_shp.dta)
(all observations in frame Lakes_shp matched)
(link to frame Lakes_shp added)
(current frame now Lakes)

            Frame name: Lakes
            Frame type: unit
          Feature type: water
         Number of obs: 3
               Unit ID: _ID
           Coordinates: _CX _CY
                  Area: <none>
    Linked shape frame: Lakes_shp

. geoframe create Roads, replace
(reading shapes from Roads_shp.dta)
(all observations in frame Roads_shp matched)
(link to frame Roads_shp added)
(current frame now Roads)

            Frame name: Roads
            Frame type: unit
          Feature type: <none>
         Number of obs: 105
               Unit ID: _ID
           Coordinates: _CX _CY
                  Area: <none>
    Linked shape frame: Roads_shp

3. Draw a map displaying state boundaries, rivers and lakes.

. geoplot (area States) (area Lakes) (line Rivers) 
Challenge-1-solution_3.png

4. Add markers and labels for cities. Distinguish the style by variable CAPITAL.

First have a look at variable CAPITAL and encode it for use in geoplot.

. frame change Cities

. tab CAPITAL

    CAPITAL |      Freq.     Percent        Cum.
------------+-----------------------------------
          C |          1        2.78        2.78
          N |          4       11.11       13.89
          Y |         31       86.11      100.00
------------+-----------------------------------
      Total |         36      100.00

. label define capital 1 "C" 2 "Y" 3 "N"

. encode CAPITAL, generate(capital) label(capital)

Now add the cities to the map. I use automatic styles by providing the city type as an argument (prefix i. instructs geoplot to treat the variable as categorical).

. geoplot (area States) (area Lakes) (line Rivers) ///
>     (point Cities i.capital, msymbol(O d T) ///
>         label(1 "Country capital" 2 "State capital" 3 "Other", reverse)) ///
>     (label Cities NAME i.capital, size(1.75) position(12))
Challenge-1-solution_5.png

I included the city names as a separate layer. An alternative would be to use the mlabel() option in the main layer. The following example also shows you how to change the colors (see help colorpalette for available color palettes).

. geoplot (area States) (area Lakes) (line Rivers) ///
>     (point Cities i.capital, msymbol(O d T) color(Darjeeling1) ///
>         mlabel(NAME) mlabsize(1.75) mlabposition(12) ///
>         label(1 "Country capital" 2 "State capital" 3 "Other", reverse))
Challenge-1-solution_6.png

Instead of assigning styles automatically, we could also add the city types as separate layers and then collect the legend keys using legend(layout()). I also switch to black color for the city names.

. geoplot (area States) (area Lakes) (line Rivers) ///
>     (point Cities if capital==3, msymbol(T) label("Other")) ///
>     (point Cities if capital==2, msymbol(d) label("State capital")) ///
>     (point Cities if capital==1, msymbol(O) label("Country capital")) ///
>     (label Cities NAME, color(black) size(1.75) position(12)) ///
>     , legend(layout(6 5 4))
Challenge-1-solution_7.png

In all of the above graphs there are issues with the positioning of the labels (e.g. labels printed on top of each other). We fix this by storing the custom positions as a variable and then provide this variable to geoplot.

. generate byte vpos = 12

. replace       vpos = 6 if NAME=="Mexicali"
(1 real change made)

. replace       vpos = 1 if NAME=="Monterrey"
(1 real change made)

. replace       vpos = 6 if NAME=="Acapulco"
(1 real change made)

. replace       vpos = 9 if NAME=="Toluca"
(1 real change made)

. replace       vpos = 6 if NAME=="Cuernavaca"
(1 real change made)

. replace       vpos = 4 if NAME=="Puebla"
(1 real change made)

. replace       vpos = 3 if NAME=="Tlaxcala"
(1 real change made)

. geoplot (area States) (area Lakes) (line Rivers) ///
>     (point Cities i.capital, msymbol(O d T) color(Darjeeling1) ///
>         label(1 "Country capital" 2 "State capital" 3 "Other", reverse)) ///
>     (label Cities NAME, color(black) size(1.75) vposition(vpos))
Challenge-1-solution_8.png

5. Now expand the plot by including roads. Distinguish style by type of road. Furthermore, try to put together a composite legend including road and city type using legend(layout()).

. frame change Roads

. tab TYPE

              TYPE |      Freq.     Percent        Cum.
-------------------+-----------------------------------
Multi-Lane Divided |         13       12.38       12.38
     Paved Divided |         24       22.86       35.24
   Paved Undivided |         68       64.76      100.00
-------------------+-----------------------------------
             Total |        105      100.00

. encode TYPE, gen(rtype)

. geoplot (area States) (area Lakes) (line Rivers) ///
>     (line Roads i.rtype, color(Salmon) lwidth(.5 .15) label(, reverse)) ///
>     (point Cities i.capital, msymbol(O d T) color(Darjeeling1) ///
>         label(1 "Country capital" 2 "State capital" 3 "Other", reverse)) ///
>     (label Cities NAME, color(black) size(1.75) vposition(vpos)) ///
>     , legen(layout(- "{bf:Cities}" 5 | - "{bf:Roads}" 4))
Challenge-1-solution_9.png