Crie cartogramas para delegados democratas na terça-feira ao estilo WSJ em R com {catchpole}

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


[Esteartigofoipublicadopelaprimeiravezem[Thisarticlewasfirstpublishedon R – rud.is, e gentilmente contribuiu para os R-blogueiros]. (Você pode relatar um problema sobre o conteúdo desta página aqui)


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.

Para as pessoas que são inteligentes o suficiente para não se aproximarem do Twitter, estou em um hiato a partir da plataforma, na medida em que lê o feed do Twitter. “Por que” não é o assunto deste post, por isso não vou abordá-lo, mas quebrei essa resolução da metade da NYE em mais de uma ocasião e estou muito feliz por ter feito isso no final de janeiro, quando peguei um RT de este tweet de Brian McGill do WSJ:

Você pode encontrá-lo aqui, e uma cópia estática de uma recente está abaixo:

Eu meio que queria tentar criar uma versão estática lamentavelmente imperfeita em R com {ggplot2}, que remexesse nos objetos XHR e javascript do URL, para ver se eu conseguia encontrar o cartograma e a fonte de dados.

A fonte de dados foi fácil, pois é um arquivo JSON carregado por XHR: https://asset.wsj.net/wsjnewsgraphics/election/2020/delegates.json.

Os bits do cartograma… eram não. Os dois dias de esforço manual de Brian ainda precisavam ser colocados em algo que entra em uma página da Web e os meios de comunicação são super talentosos em fazer visualizações interativas compactas e de carregamento rápido, o que significa que uma ferramenta que eles usam são ferramentas “webpack” para combinar muitos pequenos arquivos javascript em um. Eu fiz um rastreio, vendo se havia um JSON ou CSV de back-end em algum lugar, mas não consegui localizá-lo. No entanto, a biblioteca de cartogramas cria o SVG que você vê na página. Se você usar as Ferramentas do desenvolvedor para inspecionar qualquer elemento do SVG, copie todo o “HTML externo” do SVG e salve-o em um arquivo local:

Leia Também  Como aproveitar ao máximo as inscrições abertas

Depois de usar um proxy de interceptação, também é um recurso carregado dinamicamente: https://asset.wsj.net/wsjnewsgraphics/election/delegate-tracker/carto.svg.

Esse SVG possui três grupos de camadas superiores e algumas transformações maliciosas. Não havia como tentar uma abordagem semelhante a {statebins} para este projeto de cópia (ou seja, converter os quadrados em uma grade e mapear as coisas manualmente como Brian fez), mas eu tive uma idéia e usei o Adobe Illustrator para remover os nomes dos estados camada e a camada de polígono de plano de fundo, “nivele” a imagem (que – para simplificar demais a explicação – nivela todas as transformações) e salve-a novamente.

Em seguida, adicionei alguns metadados mágicos prescritos por svg2geojson para transformar o SVG em um arquivo GeoJSON (que {sf} pode ler!). (Essa frase acabou de fazer chocar cartógrafos e geocomputadores reais).

Agora, que eu tinha algo que R poderia usar de uma maneira mais fácil, ainda havia trabalho a ser feito. O SVG de 1 px elementos acabaram vindo como POLYGONse muitos outros pontos apareceram para o passeio (em retrospecto, acho que podem ter sido as fronteiras ao redor dos estados, mais sobre isso daqui a pouco).

Usei {purrr} e {st_coordinates} para descobrir onde todos os “polígonos” de 1 px estavam no objeto {sf} e os isolamos, depois adicionei um campo de índice (1:n, n sendo o número de quadrados de delegado para um determinado estado).

Eu li no SVG original com {xml2} e extraí os grupos de estados nomeados. Felizmente, o pedido e o número de “blocos” correspondiam ao objeto {sf} filtrado. Eu os juntei, transformei os POLYGONs de 1 px em POINTs e criei o objeto final {sf} que eu coloquei no pacote nascente {catchpole} (local abaixo). Aqui está uma rápida visualização usando plot():

library(catchpole) # hrbrmstr/catchpole

plot(delegates_map()[1])

delegates_map()
## Simple feature collection with 3979 features and 2 fields
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: -121.9723 ymin: 37.36802 xmax: -121.9581 ymax: 37.37453
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
## First 10 features:
##    state idx                   geometry
## 1     WY   1 POINT (-121.9693 37.37221)
## 2     WY   2 POINT (-121.9693 37.37212)
## 3     WY   3 POINT (-121.9691 37.37221)
## 4     WY   4 POINT (-121.9691 37.37212)
## 5     WY   5 POINT (-121.9691 37.37203)
## 6     WY   6 POINT (-121.9691 37.37194)
## 7     WY   7 POINT (-121.9691 37.37185)
## 8     WY   8  POINT (-121.969 37.37221)
## 9     WY   9  POINT (-121.969 37.37212)
## 10    WY  10  POINT (-121.969 37.37203)

Tudo o que era necessário era experimentar com os dados reais.

Leia Também  Função R pouco útil e inútil - Localizador de lua cheia

Simplifiquei bastante esse processo em {catchpole}, mas também possibilitei trabalhar com os bits individuais por conta própria. {gg_catchpole ()} buscará o JSON delegado do WSJ e criará o mapa básico para você usando o meu tema escuro “ipsum”:

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br
library(sf)
library(catchpole) # hrbrmstr/catchpole
library(hrbrthemes)
library(tidyverse)

gg_catchpole() +
  theme_ft_rc(grid="") +
  theme(legend.position = "bottom")

BÔNUS!

Agora que você possui o arquivo WSJ JSON, pode fazer outras visualizações básicas com ele:

library(hrbrthemes) 
library(waffle)
library(geofacet)
library(tidyverse)

jsonlite::fromJSON(
  url("https://asset.wsj.net/wsjnewsgraphics/election/2020/delegates.json"),
  simplifyDataFrame = FALSE
) -> del

c(
  "Biden" = "#5ac4c2",
  "Sanders" = "#63bc51",
  "Warren" = "#9574ae",
  "Buttigieg" = "#007bb1",
  "Klobuchar" = "#af973a",
  "Bloomberg" = "#AA4671",
  "Steyer" = "#4E4EAA",
  "Yang" = "#C76C48",
  "Gabbard" = "#7B8097"
) -> dcols

bind_cols(del$data$US$delCount) %>% 
  gather(candidate, delegates) %>% 
  filter(delegates > 0) %>%
  arrange(desc(delegates)) %>% 
  mutate(candidate = fct_inorder(candidate)) %>%
  ggplot(aes(candidate, delegates)) +
  geom_col(fill = ggthemes::tableau_color_pal()(1), width = 0.55) +
  labs(
    x = NULL, y = "# Delegates",
    title = "2020 Democrat POTUS Race Delegate Counts",
    subtitle = sprintf("Date: %s", Sys.Date()),
    caption = "Data source: WSJ [email protected] #rstats"
  ) +
  theme_ipsum_rc(grid="Y")

bind_cols(del$data$US$delCount) %>% 
  gather(candidate, delegates) %>% 
  filter(delegates > 0) %>%
  arrange(desc(delegates)) %>% 
  mutate(candidate = fct_inorder(candidate)) %>%
  ggplot(aes(fill=candidate, values=delegates)) +
  geom_waffle(color = "white", size = 0.5) +
  scale_fill_manual(name = NULL, values = dcols) +
  coord_fixed() +
  labs(
    x = NULL, y = "# Delegates",
    title = "2020 Democrat POTUS Race Delegate Counts",
    subtitle = sprintf("Date: %s", Sys.Date()),
    caption = "Data source: WSJ [email protected] #rstats"
  ) +
  theme_ipsum_rc(grid="") +
  theme_enhance_waffle()

state_del % 
  gather(candidate, delegates, -state) %>% 
  filter(delegates > 0) %>% 
  ggplot(aes(candidate, delegates)) +
  geom_col(aes(fill = candidate), col = NA, width = 0.55) +
  scale_fill_manual(name = NULL, values = dcols) +
  facet_geo(~state) +
  labs(
    x = NULL, y = "# Delegates",
    title = "2020 Democrat POTUS Race Delegate Counts by State",
    subtitle = sprintf("Date: %s", Sys.Date()),
    caption = "Data source: WSJ [email protected] #rstats"
  ) +
  theme_ipsum_rc(grid="Y") +
  theme(axis.text.x = element_blank()) +
  theme(panel.spacing.x = unit(0.5, "lines")) +
  theme(panel.spacing.y = unit(0.1, "lines")) +
  theme(legend.position = c(0.95, 0.1)) +
  theme(legend.justification = c(1, 0))

FIN

É necessário fazer mais trabalho no mapa e {catchpole} em si, mas há uma base suficiente para que outras pessoas possam experimentar (PRs e suas próprias postagens no blog são bem-vindas!).

Leia Também  Crise do mercado de ações: existe um efeito de bola de tênis?

W / r / t bits “mais sobre isso mais tarde”: os polígonos extras eram muito prováveis ​​fronteiras e acho que as bordas ajudariam o cartograma, mas também podemos fazer com {sf}. Também podemos adicionar uma camada para nomes de estados e / ou apenas descobrir o centróide para cada agrupamento de pontos (com {sf}) e obter lugares para rótulos dessa maneira). Não tenho certeza se terei tempo para isso (todo esse processo foi rápido, acredite ou não).

Além disso: ggiraph::geom_sf_interactive() pode ser usado como pop-up de um cara pobre para transformar isso (rapidamente) em uma peça interativa.

Se você clicar em https://git.rud.is/hrbrmstr/catchpole, encontrará o pacote e os URLs para outros sites de codificação social (embora o GitUgh tenha sofrido com o tempo de inatividade e o desempenho degradado nas últimas semanas, você deve realmente pensar sobre como mover suas cargas de trabalho para um serviço real).

Divirta-se mapeando na terça-feira e compartilhe suas criações, relações públicas, idéias etc. para o pacote onde quer que você esteja mais confortável.



Se você chegou até aqui, por que não inscreva-se para atualizações do site? Escolha seu sabor: e-mail, Twitter, RSS ou facebook …



cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br