Sesión 4. Análisis gráfico

José-Ignacio Antón


Inicio      Sesión 1      Sesión 2      Sesión 3      Sesión 4      Sesión 5      Ejercicios


1. Consejos preliminares

¿Línea de comandos o menús? No tenemos por qué elegir

Stata presenta buenas capacidades gráficas y estas han ido mejorando a lo largo del tiempo de forma muy sustancial. En Escobar et al. (2012) se realiza una aproximación al tema y tres referencias muy recomendables son Cox (2014) y Mitchell (2012), sobre la realización de gráficos con este paquete estadístico, y Schwabish (2014), que proporciona unos consejos generales sobre cómo realizar buenos gráficos.

En primer lugar, resulta muy sencillo realizar gráficos con Stata. Al mismo tiempo, elaborar figuras totalmente satisfactorias suele requerir bastante tiempo \(\rightarrow\) resulta esencial que nuestros gráficos sean reproducibles.

Así, por ejemplo, no es complicado realizar gráficos muy sofisticados con la interfaz de Stata. Su sistema de ventanas es muy intuitivo y nos permite controlar múltiples opciones.

Ejemplo de uso del sistema de ventanas para elaborar un histograma

El problema radica en la reproducibilidad: si reiniciamos el análisis gráfico o salimos del programa, tendremos que acordarnos de todas las opciones seleccionadas y, además, tendremos que repetir los cambios realizados en el editor de gráficos sobre la propia figura. \(\rightarrow\) Opción práctica: realizamos el gráfico con los menús de ventanas, empleando submit para ver cada cambio realizado y, cuando estemos satisfechos, copiamos el código y podemos reutilizarlo con adaptaciones.

Personalizando gráficos

Un avance sustancial viene dado por el paquete grstyle, que debe utilizarse conjuntamente palettes y colrspace (Jann, 2018a, 2018b). También es muy potente el paquete brewscheme. La idea de estos paquetes es que podemos definir previamente el formato de los gráficos (colores, ancho de las líneas, etc.) y, posteriormente, emplear comandos sencillos para la realización de los gráficos donde no tengamos que especificar muchas opciones.

ssc install grstyle, replace

ssc install palettes, replace

ssc install colrspace, replace

ssc install brewscheme, replace

Estos paquetes nos facilitan bastante el trabajo, pero es muy posible que queramos, en cada gráfico, añadir opciones específicas de personalización más allá de los parámetros generales.

Formatos de exportación

Stata cuenta con un formato nativo .gph con bastante calidad y que puede ser una buena opción para guardar las figuras elaboradas con la posibilidad de modificarlas luego. Además, naturalmente, podemos copiar las figuras producidas en la ventana de gráficos y pegarlas en un documento de un procesador de textos (e.g., Microsoft Word) o un programa de edición de imágenes (e.g., Microsoft Paint). Sin embargo, existe un gran número de formatos en los que Stata puede guardar los graficos: .ps, .eps, .svg, .wmf, .emf, .pdf, .png, .tif, .gif y .jpg. Formatos como .wmf y .emf son muy apropiados para aplicaciones de Microsoft Office (e.g., Microsoft Word). Sin embargo, los formatos de vectores asegura muchísima calidad y son los empleados en edición profesional (.ps, .eps, .svg, .pdf, .png). La instrucción para exportar gráficos es la siguiente:

graph export newfilename.suffix [, options]

2. Gráficos más frecuentes y potencialidades de los gráficos de Stata

En primer lugar, vamos a configurar el formato de los gráficos para que nos sirva para todas las figuras que elaboraremos con el comando grstyle. Sin embargo, como se mencionaba anteriormente, de forma habitual, necesitaremos implementar opciones adicionales. En esta sección, vamos a tratar de elaborar gráficos de alta calidad aptos para publicaciones científicas siguiendo los formatos sugeridos por Schwabish (2014) para Ciencias Sociales. Dado que el número de gráficos que Stata puede realizar no puede ser abarcado (siquiera lejanamente) en un curso de estas características, aquí nos limitamos a presentar una serie de figuras que ilustran su potencial. El proceso de realización de los mismos se fundamenta en procesos de ensayo-error y en emplear las herramientas de ayuda destacadas con anterioridad.

Gráfico de dispersión

Comenzamos por un gráfico sencillo, en el que tratamos de ver la relación el salario medio de una Comunidad Autónoma y la proporción de personas pobres (tasa de pobreza). Realizaremos en primer lugar el gráfico sin personalización alguna y, posteriormente, elaboraremos una figura con opciones personalizadas. El proceso es eminentemente learning by doing y la forma habitual de trabajo es elaborar el gráfico con los menús y obtener el código que responde a nuestras preferencias, que llevaremos al archivo .do para poder reproducir el gráfico cuando lo deseemos o reutilizarlo con otras bases de datos.

. //  Fijamos el directorio de trabajo
. 
. cd "D:\Dropbox\curso_stata\sesión4"
D:\Dropbox\curso_stata\sesión4

. 
. //  Abrimos el archivo
. 
. use "ecv18.dta", clear
(ECV 2018)
. //  Calculamos el salario medio y la tasa de pobreza por CCAA
. 
. generate rentaasa = rentamonasag + rentanomonasag
(5,362 missing values generated)

. generate nmesesasa = nmesesasatc + 0.5*nmesesasatp
(5,578 missing values generated)

. keep if rentaasa > 0 & rentaasa < .
(19,369 observations deleted)

. keep if nmesesasa > 0 & nmesesasa < .
(2,585 observations deleted)

. 
. generate salario = rentaasa/nmesesasa

. label variable salario "Salario bruto (euros/mes)"

. 
. //  Creamos la base de datos con los estadísticos de interés
. 
. collapse (mean) salario hpobreza (count) nper = pid [pweight=peso], by(region)

. 
. //  Expresamos la variable pobreza en tanto por 100
. 
. replace hpobreza = 100*hpobreza
(19 real changes made)

. 
. //  El patrón por defecto de Stata
. 
. twoway (scatter hpobreza salario), ///
> xtitle("Salario bruto (euros/mes)") ytitle("Porcentaje de personas pobres") ///
> title("Salario y pobreza por CCAA (2018)")
Gráfico por defecto

Ahora vamos a realizar el mismo gráfico de una manera mucho más personalizada.

. //  Podemos cambiar el tipo de letra
. 
. graph set window fontface       "Times New Roman"

. graph set window fontfacemono   "Times New Roman"

. graph set window fontfacesans   "Times New Roman"

. graph set window fontfaceserif  "Times New Roman"

. graph set window fontfacesymbol "Symbol"

. 
. //  Comenzamos fijando un tipo de gráfico como base o eliminar todo esa base
. 
. grstyle clear

. grstyle init

. grstyle set plain

. 
. //  Fijamos un fondo blanco
. 
. grstyle color background white

. 
. //  Definimos las dimensiones del gráfico
. 
. grstyle graphsize x 4

. grstyle graphsize y 4

. 
. //  Podemos eliminar las líneas auxiliares
. 
. grstyle set nogrid

. 
. //  Seleccionamos una paleta de colores (e.g., paleta hue)
. 
. grstyle set color hue, n(4)

. 
. //  Eliminamos la línea que rodea a la leyenda
. 
. grstyle linestyle legend none

. 
. //  Ponemos la leyenda arriba
. 
. grstyle set legend 6

. 
. //  Formato de los marcadores
. 
. grstyle symbol p circle_hollow

. 
. //  Color de los marcadores
. 
. grstyle color p1markline gs10

. 
. grstyle color p1markfill gs10

. 
. //  Color de las series
. 
. grstyle set color red green orange blue

. 
. //  Gráfico de ejemplo
. 
. twoway (scatter hpobreza salario [pweight = nper] if region != 9) ///
> (scatter hpobreza salario [pweight = nper] if region == 9, mcolor(red)) ///
> (scatter hpobreza salario [pweight = nper] if region == 9, mlabel(region) mlabsize(vsmall) mlabcolor(red) mlabposition(12) mlabgap(medsmall) mcolor(none)) ///
> (lfit hpobreza salario [pweight = nper]), ///
> title("Salario y pobreza por CCAA (2018)", size(medsmall) margin(small)) ///
> xtitle("Salario bruto (euros/mes)", margin(small) size(small)) xlabel(, format(%9,0gc) labsize(small)) ///
> ytitle("Porcentaje de personas pobres (%)", margin(small) size(small)) ylabel(, format(%2,0fc) labsize(small)) ///
> legend(off)
Gráfico de dispersión (personalizado)

Gráfico de líneas

En este ejemplo, vamos a representar el salario por grupos de edad y nivel de estudios.

. //  Abrimos el archivo
. 
. use "ecv18.dta", clear
(ECV 2018)

. 
. //  Calculamos la edad y los grupos de edad
. 
. generate edad = 2018 - anonac

. generate edadg = 1 if edad > 16 & edad <= 29
(29,586 missing values generated)

. replace edadg = 2 if edad >= 30 & edad <= 44
(6,145 real changes made)

. replace edadg = 3 if edad >= 45 & edad <= 54
(5,361 real changes made)

. replace edadg = 4 if edad >= 55 & edad <= 64
(5,159 real changes made)

. label variable edadg "Grupos de edad"

. label define edadg_lab 1 "16-29" 2 "30-44" 3 "45-54" 4 "55-64"

. label values edadg edadg_lab

. 
. //  Calculamos grupos de niveles educativos
. 
. generate educg = 1 if educ == 0 | educ == 100
(27,003 missing values generated)

. replace educg = 2 if educ == 200 | educ == 344 | educ == 353
(8,725 real changes made)

. replace educg = 3 if educ == 300 | educ == 354 | educ == 400 | educ == 450
(4,735 real changes made)

. replace educg = 4 if educ == 500
(7,969 real changes made)

. 
. label variable educg "Educación (agrupada)"

. label define educg_lab 1 "Elemental" 2 "Básica" 3 "Media" 4 "Superior"

. label values educg educg_lab

. 
. //  Calculamos el salario
. 
. generate rentaasa = rentamonasag + rentanomonasag
(5,362 missing values generated)

. generate nmesesasa = nmesesasatc + 0.5*nmesesasatp
(5,578 missing values generated)

. keep if rentaasa > 0 & rentaasa < .
(19,369 observations deleted)

. keep if nmesesasa > 0 & nmesesasa < .
(2,585 observations deleted)

. 
. generate salario = rentaasa/nmesesasa

. label variable salario "Salario bruto (euros/mes)"

. 
. //  Eliminamos valores perdidos
. 
. drop if educg == . | edadg == . | salario == .
(177 observations deleted)

. 
. //  Creamos la base de datos con los estadísticos de interés
. 
. collapse (mean) salario [pweight=peso], by(edadg educg)

. 
. //  Realizamos algunas manipulaciones para representar los datos
. 
. expand 5
(64 observations created)

. 
. bysort edadg educg: generate copy = _n

. label variable copy "Copy for graph"

. label define copy_lab 1 "Elemental" 2 "Básica" 3 "Media" 4 "Superior"

. label values copy copy_lab

. 
. forvalues i = 1(1)4 {
  2.   drop if educg == `i' & copy == `i'
  3. 
. }
(4 observations deleted)
(4 observations deleted)
(4 observations deleted)
(4 observations deleted)

. 
. bysort edadg educg: egen meducg =mean(educg)

. 
. replace educg = 5 if copy == 5
(16 real changes made)

. 
. replace copy = meducg if copy == 5
(16 real changes made)

. 
. //  Realizamos el gráfico de interés
. 
. twoway ///
> (line salario edadg if educg == 1, lcolor(gs10)) ///
> (line salario edadg if educg == 2, lcolor(gs10)) ///
> (line salario edadg if educg == 3, lcolor(gs10)) ///
> (line salario edadg if educg == 4, lcolor(gs10)) ///
> (line salario edadg if educg == 5, lcolor(blue)), ///
> ytitle("Salario mensual", size(small) margin(small)) ylabel(, labsize(small) format(%5,0fc)) ///
> xtitle("Edad", size(small) margin(small)) xlabel(1 "16-29" 2 "30-44" 3 "45-54" 4 "55-64", labsize(small)) ///
> by(copy, note("") legend(off) imargin(medsmall) title("Salario por edad y nivel educativo (2018)", size(medsmall) margin(small))) ///
> subtitle(, size(small)) ///
> xsize(4) ysize(4)
Gráfico de líneas

Gráfico de puntos

En este subapartado, elaboramos una figura que muestra la tasa de empleo por sexo y nivel educativo en España.

. //  Abrimos el archivo
. 
. use "ecv18.dta", clear
(ECV 2018)

. 
. //  Calculamos la edad
. 
. generate edad = 2018 - anonac

. 
. //  Calculamos la tasa de empleo
. 
. gen empleo = 0 if edad >= 18 & edad <= 64
(13,265 missing values generated)

. recode empleo (0 = 1) if sitact == 1
(12867 changes made to empleo)

. 
. //  Calculamos los grupos de niveles educativos
. 
. generate educg = 1 if educ == 0 | educ == 100
(27,003 missing values generated)

. replace educg = 2 if educ == 200 | educ == 344 | educ == 353
(8,725 real changes made)

. replace educg = 3 if educ == 300 | educ == 354 | educ == 400 | educ == 450
(4,735 real changes made)

. replace educg = 4 if educ == 500
(7,969 real changes made)

. 
. label variable educg "Educación (agrupada)"

. label define educg_lab 1 "Educación elemental" 2 "Educación básica" 3 "Educación media" 4 "Educación superior"

. label values educg educg_lab

. 
. keep if empleo < . & educg < .
(13,442 observations deleted)

. 
. //  Creamos la base de datos con los estadísticos de interés
. 
. collapse (mean) empleo [pweight=peso], by(sexo educg)

. 
. //  Expresamos la tasa de empleo en tanto por 100
. 
. replace empleo = 100*empleo
(8 real changes made)

. 
. //  Elaboramos el gráfico de interés
. 
. twoway ///
> (line educg empleo if educg == 1, lcolor(black)) ///
> (line educg empleo if educg == 2, lcolor(black)) ///
> (line educg empleo if educg == 3, lcolor(black)) ///
> (line educg empleo if educg == 4, lcolor(black)) ///
> (scatter educg empleo if sexo == 1, mcolor(navy) msize(4-pt) msymbol(circle) mlabcolor()) ///
> (scatter educg empleo if sexo == 2, mcolor(orange) msize(4-pt) msymbol(circle) mlabel(educg) mlabsize(small) mlabcolor(black) mlabposition(9) mlabgap(small)), ///
> title("Tasa de empleo por sexo y nivel educativo en España (2018)", size(medsmall) margin(small)) ///
> yscale(off) ylabel(0(1)4) ///
> xtitle("Porcentaje de personas empleadas (%)", margin(small) size(small)) xlabel(0(20)100, labsize(vsmall)) ///
> legend(on order(5 "Hombres" 6 "Mujeres") size(vsmall) color(black) nobox position(11))
Gráfico de puntos

Gráfico de barras

A continuación, mostramos la tasa de pobreza por nivel educativo y sexo en España en el año 2018. Además, en este ejemplo, vamos a usar el editor de gráficos de Stata.

. //  Abrimos el archivo
. 
. use "ecv18.dta", clear
(ECV 2018)

. 
. //  Calculamos los grupos de niveles educativos
. 
. generate educg = 1 if educ == 0 | educ == 100
(27,003 missing values generated)

. replace educg = 2 if educ == 200 | educ == 344 | educ == 353
(8,725 real changes made)

. replace educg = 3 if educ == 300 | educ == 354 | educ == 400 | educ == 450
(4,735 real changes made)

. replace educg = 4 if educ == 500
(7,969 real changes made)

. 
. label variable educg "Educación (agrupada)"

. label define educg_lab 1 "Educación elemental" 2 "Educación básica" 3 "Educación media" 4 "Educación superior"

. label values educg educg_lab

. 
. keep if educg < .
(5,574 observations deleted)

. 
. //  Creamos la base de datos con los estadísticos de interés
. 
. collapse (mean) hpobreza [pweight=peso], by(sexo educg)

. 
. //  Expresamos la tasa de pobreza en tanto por 100
. 
. replace hpobreza = 100*hpobreza
(8 real changes made)

. 
. //  Reordenamos los datos para representarlos
. 
. reshape wide hpobreza, i(educg) j(sexo)
(j = 1 2)

Data                               Long   ->   Wide
─────────────────────────────────────────────────────────────────────────────
Number of observations                8   ->   4           
Number of variables                   3   ->   3           
j variable (2 values)              sexo   ->   (dropped)
xij variables:
                               hpobreza   ->   hpobreza1 hpobreza2
─────────────────────────────────────────────────────────────────────────────

. 
. //  Elaboramos el gráfico de interés
. 
. graph bar (asis) hpobreza1 hpobreza2, ///
> over(educg, relabel(1 "Elementales" 2 "Básicos" 3 "Medios" 4 "Superiores") label(labsize(vsmall))) ///
> bar(1, fcolor(navy) lcolor(none)) ///
> bar(2, fcolor(orange) lcolor(none)) ///
> ytitle(Tasa de pobreza (%)) ytitle(, size(vsmall) margin(sides)) ylabel(0(10)50, labsize(vsmall) nogrid) ///
> title(Pobreza por sexo y nivel educativo en España (2018), size(medsmall) margin(top_bottom)) legend(off) ///
> b1title("Nivel de estudios", size(vsmall) margin(top_bottom))

. 
. gr_edit plotregion1.AddTextBox added_text editor 35.8934560474294 10.62503501939819

. gr_edit plotregion1.added_text_new = 1

. gr_edit plotregion1.added_text_rec = 1

. gr_edit plotregion1.added_text[1].style.editstyle  angle(default) size( sztype(points) val(2) allow_pct(1)) ///
> color(navy) horizontal(left) vertical(middle) margin( gleft( sztype(relative) val(0) allow_pct(1)) ///
> gright( sztype(relative) val(0) allow_pct(1)) gtop( sztype(relative) val(0) allow_pct(1)) ///
> gbottom( sztype(relative) val(0) allow_pct(1))) linegap( sztype(relative) val(0) allow_pct(1)) ///
> drawbox(no) boxmargin( gleft( sztype(relative) val(0) allow_pct(1)) ///
> gright( sztype(relative) val(0) allow_pct(1)) gtop( sztype(relative) val(0) allow_pct(1)) ///
> gbottom( sztype(relative) val(0) allow_pct(1))) fillcolor(bluishgray) ///
> linestyle( width( sztype(relative) val(.2) allow_pct(1)) color(black) pattern(solid) align(inside)) box_alignment(east) editcopy

. gr_edit plotregion1.added_text[1].style.editstyle size(vsmall) editcopy

. gr_edit plotregion1.added_text[1].text = {}

. gr_edit plotregion1.added_text[1].text.Arrpush Hombres

. 
. gr_edit plotregion1.AddTextBox added_text editor 32.6954873184468 19.95200785068754

. gr_edit plotregion1.added_text_new = 2

. gr_edit plotregion1.added_text_rec = 2

. gr_edit plotregion1.added_text[2].style.editstyle  angle(default) size( sztype(relative) val(4.1667) allow_pct(1)) ///
> color(navy) horizontal(left) vertical(middle) margin( gleft( sztype(relative) val(0) allow_pct(1)) ///
> gright( sztype(relative) val(0) allow_pct(1)) gtop( sztype(relative) val(0) allow_pct(1)) ///
> gbottom( sztype(relative) val(0) allow_pct(1))) ///
> linegap( sztype(relative) val(0) allow_pct(1)) drawbox(no) boxmargin( gleft( sztype(relative) val(0) allow_pct(1)) ///
> gright( sztype(relative) val(0) allow_pct(1)) gtop( sztype(relative) val(0) allow_pct(1)) ///
> gbottom( sztype(relative) val(0) allow_pct(1))) fillcolor(bluishgray) ///
> linestyle( width( sztype(relative) val(.2) allow_pct(1)) color(black) pattern(solid) align(inside)) box_alignment(east) editcopy

. gr_edit plotregion1.added_text[2].style.editstyle size(vsmall) editcopy

. gr_edit plotregion1.added_text[2].text = {}

. gr_edit plotregion1.added_text[2].text.Arrpush Mujeres

. gr_edit plotregion1.added_text[2].style.editstyle color(orange) editcopy

. 
. gr_edit plotregion1.AddLine added_lines editor 6.412853740751393 30.4815089676127 6.412853740751393 35.64745845289226

. gr_edit plotregion1.added_lines_new = 1

. gr_edit plotregion1.added_lines_rec = 1

. gr_edit plotregion1.added_lines[1].style.editstyle  linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(navy) pattern(solid) align(inside)) headstyle( symbol(circle) linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(navy) pattern(solid) align(inside)) fillcolor(navy) size( sztype(relative) val(1.04166) allow_pct(1)) ///
> angle(stdarrow) symangle(zero) backsymbol(none) backline( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(navy) pattern(solid) align(inside)) backcolor(navy) backsize( sztype(relative) val(0) allow_pct(1)) ///
> backangle(stdarrow) backsymangle(zero)) headpos(neither) editcopy

. 
. gr_edit plotregion1.AddLine added_lines editor 6.412853740751393 35.56545925471323 9.872859791068407 35.56545925471323

. gr_edit plotregion1.added_lines_new = 2

. gr_edit plotregion1.added_lines_rec = 2

. gr_edit plotregion1.added_lines[2].style.editstyle  linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(navy) pattern(solid) align(inside)) headstyle( symbol(circle) linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(navy) pattern(solid) align(inside)) fillcolor(navy) size( sztype(relative) val(1.04166) allow_pct(1)) ///
> angle(stdarrow) symangle(zero) backsymbol(none) backline( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(black) pattern(solid) align(inside)) backcolor(black) backsize( sztype(relative) val(0) allow_pct(1)) ///
> backangle(stdarrow) backsymangle(zero)) headpos(head) editcopy

. 
. gr_edit plotregion1.AddLine added_lines editor 15.89026161770668 27.44753863498822 15.89026161770668 32.2854913275516

. gr_edit plotregion1.added_lines_new = 3

. gr_edit plotregion1.added_lines_rec = 3

. gr_edit plotregion1.added_lines[3].style.editstyle  linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(orange) pattern(solid) align(inside)) headstyle( symbol(circle) linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(orange) pattern(solid) align(inside)) fillcolor(orange) size( sztype(relative) val(1.04166) allow_pct(1)) ///
> angle(stdarrow) symangle(zero) backsymbol(none) backline( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(black) pattern(solid) align(inside)) backcolor(navy) backsize( sztype(relative) val(0) allow_pct(1)) ///
> backangle(stdarrow) backsymangle(zero)) headpos(neither) editcopy

. 
. gr_edit plotregion1.AddLine added_lines editor 15.89026161770668 32.28549132755161 18.74852748535989 32.28549132755161

. gr_edit plotregion1.added_lines_new = 4

. gr_edit plotregion1.added_lines_rec = 4

. gr_edit plotregion1.added_lines[4].style.editstyle  linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(orange) pattern(solid) align(inside)) headstyle( symbol(circle) linestyle( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(orange) pattern(solid) align(inside)) fillcolor(orange) size( sztype(relative) val(1.04166) allow_pct(1)) ///
> angle(stdarrow) symangle(zero) backsymbol(none) backline( width( sztype(relative) val(.2) allow_pct(1)) ///
> color(black) pattern(solid) align(inside)) backcolor(black) backsize( sztype(relative) val(0) allow_pct(1)) ///
> backangle(stdarrow) backsymangle(zero)) headpos(head) editcopy
Gráfico de barras

La última parte del código corresponde al editor de gráficos de Stata, que permite hacer cambios manualmente. Si queremos asegurar que el gráfico es reproducible podemos seguir estos pasos:

Paso 1. Abrimos el gráfico en el editor.

Paso 2. Pulsamos Start recording.

Paso 3. Realizamos los cambios que queramos (añadir cuadros de texto, flechas, etc.).

Paso 4. Finalizamos la grabación pulsando End recording.

Paso 5. Abrimos el archivo .grec creado en el blog de notas (o el propio editor de archivos .do de Stata).

Paso 6. Copiamos el código y relevante al arhivo .do tras el grafico, eliminamos el . e incluimos antes de cada instrucción gr_edit seguido de un espacio.

Modificación de gráficos con el editor de Stata

Funciones de densidad

Se trata de uno de los fuertes de Stata, que es complicado de abordar con otro tipo de programas (e.g., Microsoft Excel). En este caso, vamos a representar las funciones de densidad del salario mensual de las personas con educación elemental y educación superior.

. //  Abrimos el archivo
. 
. use "ecv18.dta", clear
(ECV 2018)

. 
. //  Calculamos el salario
. 
. generate rentaasa = rentamonasag + rentamonasag
(5,362 missing values generated)

. generate nmesesasa = nmesesasatc + 0.5*nmesesasatp
(5,578 missing values generated)

. keep if rentaasa > 0 & rentaasa < .
(19,416 observations deleted)

. keep if nmesesasa > 0 & nmesesasa < .
(2,540 observations deleted)

. 
. generate salario = rentaasa/nmesesasa

. label variable salario "Salario bruto (euros/mes)"

. 
. //  Lo expresamos en logaritmos
. 
. generate logsalario = ln(salario)

. label variable logsalario "Salario en logaritmos"

. 
. //  Calculamos los grupos de niveles educativos
. 
. generate educg = 1 if educ == 0 | educ == 100
(10,934 missing values generated)

. replace educg = 2 if educ == 200 | educ == 344 | educ == 353
(3,331 real changes made)

. replace educg = 3 if educ == 300 | educ == 354 | educ == 400 | educ == 450
(2,509 real changes made)

. replace educg = 4 if educ == 500
(5,094 real changes made)

. 
. label variable educg "Educación (agrupada)"

. label define educg_lab 1 "Educación elemental" 2 "Educación básica" 3 "Educación media" 4 "Educación superior"

. label values educg educg_lab

. 
. keep if educg < .
(0 observations deleted)

. 
. //  Eliminamos valores perdidos
. 
. keep if logsalario < . | educg < .
(0 observations deleted)

. 
. //  Elaboramos el gráfico de interés
. 
. twoway ///
> (kdensity logsalario if educg == 1 [aweight = peso]) ///
> (kdensity logsalario [aweight = educg == 4]), ///
> ytitle("Densidad", size(vsmall) margin(sides)) ylabel(, labsize(vsmall) format(%02,1fc)) ///
> xtitle("Salario bruto en logaritmos (euros/mes)", size(vsmall) margin(top_bottom)) xlabel(, labsize(vsmall)) ///
> title("Función de densidad del salario" "por nivel educativo en España (2018)", size(small) margin(top_bottom)) ///
> legend(on order(1 "Educación elemental" 2 "Educación superior") cols(1) size(vsmall) position(10) ring(0))
Gráfico de densidad

4. Elaboración de mapas

No es, desde luego, el mejor software para esta tarea, pero, sin embargo, existen algunos comandos que pueden ser muy útiles para usuarios poco exigentes (e.g., investigadores en Ciencias Sociales para los que los mapas no son centrales). Existen varios paquetes para esta tarea, como spmap o geo2xy. En este curso, emplearemos el primero de ellos, spmap. Podemos encontrar una buena introducción al uso de este paquete en Wiedemann (2020). La mejor referencia sobre elaboración de mapas en Stata es posiblemente la colección de guías y tutoriales de Asjad Naqvi. spmap requiere la instalación adicional de shp2dta y mif2dta. Así, podemos instalar todos los parquetes necesarios de la siguiente forma:

ssc install spmap, replace

ssc install shp2dta, replace

ssc install mif2dta, replace

Con spmap, Stata puede manejar dos tipos de formatos gráficos: ESRI shapefiles (incluye un archivo .shp de coordenadas, un archivo .shx, un índice, y un archivo .dbf, con códigos) y el MapInfo Interchange Format files (que comprende un archivo .mif con las coordenadas y un archivo .mid con los códigos). El manejo del primer tipo de formato es, con frecuencia, más sencillo. Para explorar las capacidades de Stata en esta área, vamos a realizar un mapa de España por Comunidades Autónomas con su tasa de pobreza.

Procedemos en varios pasos.

Paso 1. Buscamos los ESRI shapefiles que precisamos. En este caso, podemos encontrarlos en muchos lugares. El mapa “oficial” se encuentra en el Centro Nacional de Información Geográfica, los copiamos a la carpeta de trabajo y descomprimimos la carpeta. Nuestro interés radica en la carpeta Recintos autonómicos: poligonos_autonomicas_inspire_peninbal_ etrs89. Nos vamos a limitar a la península, por simplicidad. Extraemos sus archivos y los situamos en la carpeta de trabajo.

Paso 2. Creamos los archivos de atributos y coordenadas con la siguiente instrucción:

. shp2dta using "recintos_autonomicas_inspire_peninbal_etrs89", data("ccaa_attr.dta") coord("ccaa_coord.dta") genid(stid) gencentroids(cc) replace
type: 5

Paso 3. Con nuestra base de datos, generamos un archivo que podamos unir al de atributos empleando la variable stid del fichero ccaa_attr.dta. Prescindimos, además, de Ceuta y Melilla, por simplicidad.

. //  Abrimos el archivo
. 
. use "ecv18.dta", clear
(ECV 2018)

. 
. //  Calculamos los estadísticos de interés
. 
. collapse (mean) hpobreza [pweight = peso], by(region)

. 
. //  Expresamos la tasa de pobreza en tanto por 100
. 
. replace hpobreza = 100*hpobreza
(19 real changes made)

. 
. //  Eliminamos Canarias
. 
. drop if region == 19
(1 observation deleted)

. 
. //  Recodificamos las regiones para enlazar con la variable stid de ccaa_attr.dta
. 
. recode region (1=10) (2=18) (3=16) (4=6) (5=7) (6=5) (7=19) (8=9) (9=15) (10=14) (11=11) (12=13) (13=12) (14=17) (15=20) (16=8) (17=3) (18=4)
(17 changes made to region)

. 
. //  Eliminamos las etiquetas de los valores para evitar confusiones
. 
. label drop region_lab

. 
. //  Cambiamos el nombre de la variable de enlace
. 
. rename region stid

. 
. //  Eliminamos las regiones que no queremos representar
. 
. drop if stid <= 4
(2 observations deleted)

. 
. save "ccaa_pobreza.dta", replace
file ccaa_pobreza.dta saved

Paso 4. De forma opcional, podemos crear un archivo para etiquetar las regiones.

. //  Creamos un archivo con etiquetas.
. 
. use "ccaa_attr.dta", clear

. merge 1:1 stid using "ccaa_pobreza.dta", keep(match)

    Result                      Number of obs
    ─────────────────────────────────────────
    Not matched                             0
    Matched                                16  (_merge==3)
    ─────────────────────────────────────────

. keep stid hpobreza x_cc y_cc

. format hpobreza %02,1fc

. save "ccaa_labels.dta", replace
file ccaa_labels.dta saved

Paso 5. Realizamos una fusión de nuestro archivo ccaa_pobreza.dta con el archivo ccaa_attr.dta empleando como enlace la variable stid.

. //  Abrimos el archivo ccaa_attr.dta
. 
. use "ccaa_attr.dta", clear

. 
. //  Realizamos la fusión con merge
. 
. merge 1:1 stid using "ccaa_pobreza.dta", keep(match)

    Result                      Number of obs
    ─────────────────────────────────────────
    Not matched                             0
    Matched                                16  (_merge==3)
    ─────────────────────────────────────────

. 

Paso 6. Creamos el gráfico con spmap.

. //  Creamos el mapa
. 
. spmap hpobreza using "ccaa_coord.dta", ///
> id(stid) fcolor(Reds) ///
> ocolor(black ..) osize(thin ..)  ///
> legend(size(vsmall) position(5) label(2 "0-10") label(3 "10-20") label(4 "20-30") label(5 "30-40")) ///
> clmethod(custom)  clbreaks(0 10 20 30 40) ///
> legtitle("Tasa de pobreza (%)") ///
> title("Tasa de pobreza en España por CCAA (2018)", size(small)) name("pobreza2018", replace) ///
> label(data("ccaa_labels.dta") label(hpobreza) xcoord(x_cc) ycoord(y_cc) color(black) size(vsmall) length(4)) ///
> freestyle yscale(off) xscale(off)

. 
. //    Usamos el editor de Stata para ajustar el tamaño
. 
. gr_edit style.editstyle declared_ysize(5) editcopy

. gr_edit style.editstyle declared_xsize(7) editcopy
Mapa con el paquete spmap

References

Cox, N. J. (2014). Speaking Stata graphics. Stata Press.
Escobar, M., Fernández-Macías, E., & Bernardi, F. (2012). Análisis de datos con Stata (2nd ed.). Centro de Investigaciones Sociólogicas.
Jann, B. (2018a). Customizing Stata graphs made easy (part 1). Stata Journal, 3(18), 491–502.
Jann, B. (2018b). Customizing Stata graphs made easy (part 2). Stata Journal, 4(19), 786–802.
Mitchell, M. N. (2012). A visual guide to Stata graphics (3rd ed.). Stata Press.
Schwabish, J. A. (2014). An economists guide to visualizing data. Journal of Economic Perspectives, 28(1), 209–234.
Wiedemann, V. (2020). Creating maps in Stata [Coder's corner]. Centre for the Study of African Economy. https://www.csae.ox.ac.uk/materials/coderscorner/1037/coderscornerht20week2fm.pdf