Browse Source

statebins reimagined

master
boB Rudis 7 years ago
parent
commit
5c63e18785
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 10
      DESCRIPTION
  2. 9
      NAMESPACE
  3. 3
      NEWS.md
  4. 2
      R/aaa.R
  5. 106
      R/statebins-continuous.R
  6. 119
      R/statebins-manual.R
  7. 5
      R/statebins-package.R
  8. 140
      R/statebins.R
  9. 24
      R/theme-statebin.R
  10. 12
      R/util.R
  11. 236
      README.Rmd
  12. BIN
      README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-1.png
  13. BIN
      README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-2.png
  14. BIN
      README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-3.png
  15. BIN
      README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-4.png
  16. BIN
      README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-5.png
  17. BIN
      README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-6.png
  18. 268
      README.md
  19. BIN
      README_files/figure-gfm/unnamed-chunk-3-1.png
  20. BIN
      README_files/figure-gfm/unnamed-chunk-3-2.png
  21. BIN
      README_files/figure-gfm/unnamed-chunk-3-3.png
  22. BIN
      README_files/figure-gfm/unnamed-chunk-3-4.png
  23. BIN
      README_files/figure-gfm/unnamed-chunk-3-5.png
  24. BIN
      README_files/figure-gfm/unnamed-chunk-3-6.png
  25. BIN
      README_files/figure-gfm/unnamed-chunk-4-1.png
  26. 80
      man/statebins.Rd
  27. 74
      man/statebins_continuous.Rd
  28. 83
      man/statebins_manual.Rd
  29. 18
      man/theme_statebins.Rd
  30. 52
      tmp/election2012.csv
  31. BIN
      tmp/household.gif
  32. BIN
      tmp/household2000.png
  33. BIN
      tmp/household2001.png
  34. BIN
      tmp/household2002.png
  35. BIN
      tmp/household2003.png
  36. BIN
      tmp/household2004.png
  37. BIN
      tmp/household2005.png
  38. BIN
      tmp/household2006.png
  39. BIN
      tmp/household2007.png
  40. BIN
      tmp/household2008.png
  41. BIN
      tmp/household2009.png
  42. BIN
      tmp/household2010.png
  43. BIN
      tmp/household2011.png
  44. BIN
      tmp/household2012.png
  45. BIN
      tmp/statebins-composite.png

10
DESCRIPTION

@ -2,7 +2,7 @@ Package: statebins
Type: Package Type: Package
Title: Create 'U.S.' Uniform Square State Cartogram Heatmaps Title: Create 'U.S.' Uniform Square State Cartogram Heatmaps
Version: 1.3.0 Version: 1.3.0
Date: 2018-11-14 Date: 2017-11-14
Author: Bob Rudis (bob@rud.is) Author: Bob Rudis (bob@rud.is)
Maintainer: Bob Rudis <bob@rud.is> Maintainer: Bob Rudis <bob@rud.is>
Description: Cartogram heatmaps are an alternative to choropleth maps for 'USA' States Description: Cartogram heatmaps are an alternative to choropleth maps for 'USA' States
@ -17,12 +17,12 @@ URL: https://github.com/hrbrmstr/statebins
BugReports: https://github.com/hrbrmstr/statebins/issues BugReports: https://github.com/hrbrmstr/statebins/issues
License: MIT + file LICENSE License: MIT + file LICENSE
Suggests: Suggests:
testthat testthat,
viridis,
RColorBrewer
Depends: Depends:
R (>= 3.2.0), R (>= 3.2.0),
Imports: Imports:
ggplot2 (>= 2.2.0), ggplot2 (>= 2.2.0),
scales (>= 0.5.0), scales (>= 0.5.0)
viridis,
RColorBrewer (>= 1.1-2)
RoxygenNote: 6.0.1 RoxygenNote: 6.0.1

9
NAMESPACE

@ -1,11 +1,9 @@
# Generated by roxygen2: do not edit by hand # Generated by roxygen2: do not edit by hand
export(statebins) export(statebins)
export(statebins_continuous) export(theme_statebins)
export(statebins_manual)
import(RColorBrewer)
import(viridis)
importFrom(ggplot2,aes) importFrom(ggplot2,aes)
importFrom(ggplot2,aes_)
importFrom(ggplot2,aes_string) importFrom(ggplot2,aes_string)
importFrom(ggplot2,coord_equal) importFrom(ggplot2,coord_equal)
importFrom(ggplot2,element_blank) importFrom(ggplot2,element_blank)
@ -17,17 +15,14 @@ importFrom(ggplot2,geom_tile)
importFrom(ggplot2,ggplot) importFrom(ggplot2,ggplot)
importFrom(ggplot2,ggplotGrob) importFrom(ggplot2,ggplotGrob)
importFrom(ggplot2,ggtitle) importFrom(ggplot2,ggtitle)
importFrom(ggplot2,guide_legend)
importFrom(ggplot2,guides) importFrom(ggplot2,guides)
importFrom(ggplot2,labs) importFrom(ggplot2,labs)
importFrom(ggplot2,rel) importFrom(ggplot2,rel)
importFrom(ggplot2,scale_color_manual) importFrom(ggplot2,scale_color_manual)
importFrom(ggplot2,scale_fill_brewer) importFrom(ggplot2,scale_fill_brewer)
importFrom(ggplot2,scale_fill_gradientn)
importFrom(ggplot2,scale_fill_manual) importFrom(ggplot2,scale_fill_manual)
importFrom(ggplot2,scale_x_continuous) importFrom(ggplot2,scale_x_continuous)
importFrom(ggplot2,scale_y_continuous) importFrom(ggplot2,scale_y_continuous)
importFrom(ggplot2,scale_y_reverse)
importFrom(ggplot2,theme) importFrom(ggplot2,theme)
importFrom(ggplot2,theme_bw) importFrom(ggplot2,theme_bw)
importFrom(scales,alpha) importFrom(scales,alpha)

3
NEWS.md

@ -1,5 +1,8 @@
# statebins 1.3.0 # statebins 1.3.0
* Added support for `VI`/`Virgin Islands` * Added support for `VI`/`Virgin Islands`
* Supports auto-computation of when to use light & dark label colors
* New `theme_statebins()`
* Completely re-designed the interface and will not be providing backwards-compatibility.
# statebins 1.2.2 # statebins 1.2.2
* CRAN update * CRAN update

2
R/aaa.R

@ -3,7 +3,7 @@ state_coords <- structure(list(abbrev = c("AL", "AK", "AZ", "AR", "CA", "CO",
"KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE",
"NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA",
"RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY",
"PR", "VI"), "PR", "VI", "NYC"),
state = c("Alabama", "Alaska", "Arizona", "Arkansas", state = c("Alabama", "Alaska", "Arizona", "Arkansas",
"California", "Colorado", "Connecticut", "District of Columbia", "California", "Colorado", "Connecticut", "District of Columbia",
"Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois",

106
R/statebins-continuous.R

@ -1,106 +0,0 @@
#' Create a new ggplot-based "statebin" chart for USA states (continuous scale)
#'
#' \code{statebins()} creates "statebin" charts in the style of \url{http://bit.ly/statebins}
#'
#' This version uses a continuous scale based on \code{RColorBrewer} scales
#' (passing in a 6 element \code{RColorBrewer} palette to \code{scale_fill_gradientn}).
#'
#' The function minimally expects the caller to pass in a data frame that:
#'
#' \itemize{
#' \item has one column of all state abbreviationis (all caps, including \code{DC} &
#' \code{PR} ) or a column of state names (standard capitalization) named \code{state}
#' \item has another column of values named \code{value}
#' }
#'
#' Doing so will create a "statebin" chart with 5 breaks and return a \code{ggplot2} object.
#'
#' You can use a different column for the state names and values by changing \code{state_col}
#' and \code{value_col} accordingly.
#'
#' To add a title, change \code{plot_title} to anything but an empty atomic string vector (i.e. \code{""})
#' and set \code{title_position} to "\code{top}" or "\code{bottom}". Choosing "\code{bottom}"
#' will cause \code{statebins} to use the X axis title placeholder.
#'
#' @param state_data data frame of states and values to plot
#' @param state_col column name in \code{state_data} that has the states. no duplicates
#' and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}")
#' @param value_col column name in \code{state_data} that holds the values to be plotted
#' @param text_color default "\code{black}". Size 1 for global color across all tiles or
#' a vector of colors the same length as the number of states you passed in.
#' Use the sort order for the states as they are sorted before being plotted.
#' @param font_size font size (default = \code{3})
#' @param state_border_col default "\code{white}" - this creates the "spaces" between boxes
#' @param legend_title title for the legend
#' @param legend_position "\code{none}", "\code{top}", "\code{left}", "\code{right}" or
#' "\code{bottom}" (defaults to "\code{top}")
#' @param brewer_pal which named \code{RColorBrewer} palette to use (defaults to "PuBu")
#' @param plot_title title for the plot
#' @param title_position where to put the title ("\code{bottom}" or "\code{top}" or ""
#' for none); if "\code{bottom}", you get back a grob vs a ggplot object
#' @return ggplot2 object or grob
#' @export
#' @examples
#' \dontrun{
#' data(USArrests)
#' USArrests$state <- rownames(USArrests)
#' statebins_continuous(USArrests, value_col="Murder", text_color="black", font_size=3,
#' legend_title = "Murder", legend_position="bottom")
#' }
statebins_continuous <- function(state_data, state_col="state", value_col="value",
text_color="black", font_size=3,
state_border_col="white",
legend_title="Legend", legend_position="top",
brewer_pal="PuBu", plot_title="", title_position="bottom") {
if (!title_position %in% c("", "top", "bottom")) {
stop("'title_position' must be either blank, 'top' or 'bottom'")
}
if (!legend_position %in% c("", "none", "top", "bottom")) {
stop("'legend_position' must be either blank, 'none', 'top' or 'bottom'")
}
state_data <- data.frame(state_data, stringsAsFactors=FALSE)
if (max(nchar(state_data[,state_col])) == 2) {
merge.x <- "abbrev"
} else {
merge.x <- "state"
}
state_data <- validate_states(state_data, state_col, merge.x)
st.dat <- merge(state_coords, state_data, by.x=merge.x, by.y=state_col, all.y=TRUE)
gg <- ggplot(st.dat, aes_string(x="col", y="row", label="abbrev"))
gg <- gg + geom_tile(aes_string(fill=value_col))
gg <- gg + geom_tile(color=state_border_col,
aes_string(fill=value_col), size=3, show.legend=FALSE)
gg <- gg + geom_text(color=text_color, size=font_size)
gg <- gg + scale_y_reverse()
gg <- gg + scale_fill_gradientn(colours = brewer.pal(6, brewer_pal), name=legend_title)
gg <- gg + coord_equal()
gg <- gg + labs(x=NULL, y=NULL, title=NULL)
gg <- gg + theme_bw()
gg <- gg + theme(legend.position=legend_position)
gg <- gg + theme(panel.border=element_blank())
gg <- gg + theme(panel.grid=element_blank())
gg <- gg + theme(panel.background=element_blank())
gg <- gg + theme(axis.ticks=element_blank())
gg <- gg + theme(axis.text=element_blank())
if (plot_title != "") {
if (title_position == "bottom") {
gg <- gg + labs(x=plot_title)
gg <- gg + theme(axis.text.x=element_text(hjust=0.5, size=ggplot2::rel(1.2), angle=0))
} else {
gg <- gg + ggtitle(plot_title)
}
}
return(gg)
}

119
R/statebins-manual.R

@ -1,119 +0,0 @@
#' Create a new ggplot-based "statebin" chart for USA states (manually colored)
#'
#' \code{statebins()} creates "statebin" charts in the style of \url{http://bit.ly/statebins}
#'
#' This version uses manual colors (i.e. pass in a column that defines the color per-state)
#'
#' The function minimally expects the caller to pass in a data frame that:
#'
#' \itemize{
#' \item has one column of all state abbreviationis (all caps, including \code{DC} &
#' \code{PR} or a column of state names (standard capitalization) named \code{state}
#' \item has another column of colors named \code{color}
#' }
#'
#' Doing so will create a "statebin" chart with the colors specified as a ggplot2 object.
#'
#' You can use a different column for the state names and colors by changing \code{state_col}
#' and \code{color_col} accordingly.
#'
#' To add a title, change \code{plot_title} to anything but an empty atomic string vector (i.e. \code{""})
#' and set \code{title_position} to "\code{top}" or "\code{bottom}". Choosing "\code{bottom}"
#' will cause \code{statebins} to use the X axis title placeholder.
#'
#' @param state_data data frame of states and values to plot
#' @param state_col column name in \code{state_data} that has the states. no duplicates
#' and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}")
#' @param color_col column name in \code{state_data} that holds the colors to be used
#' @param text_color default "\code{black}". Size 1 for global color across all tiles or
#' a vector of colors the same length as the number of states you passed in.
#' Use the sort order for the states as they are sorted before being plotted.
#' @param font_size font size (default = \code{3})
#' @param state_border_col default "\code{white}" - this creates the "spaces" between boxes
#' @param labels labels for the legend (should be the same number as distinct colors in
#' \code{color_col}); \code{NULL} == no labels/legend
#' @param legend_title title for the legend
#' @param legend_position "\code{none}", "\code{top}", "\code{left}", "\code{right}" or
#' "\code{bottom}" (defaults to "\code{top}")
#' @param plot_title title for the plot
#' @param title_position where to put the title ("\code{bottom}" or "\code{top}" or ""
#' for none); if "\code{bottom}", you get back a grob vs a ggplot object
#' @return ggplot2 object or grob
#' @export
#' @examples
#' \dontrun{
#' library(httr)
#' library(dplyr)
#' election_2012 <-
#' GET("https://raw.githubusercontent.com/hrbrmstr/statebins/master/tmp/election2012.csv")
#' results <- read.csv(textConnection(content(election_2012, as="text")),
#' header=TRUE, stringsAsFactors=FALSE)
#' results <- results %>%
#' mutate(color=ifelse(is.na(Obama), "#2166ac", "#b2182b")) %>%
#' select(state, color)
#' results %>%
#' statebins_manual(font_size=4,
#' text_color = "white", labels=c("Romney", "Obama"),
#' legend_position="right", legend_title="Winner")
#' }
statebins_manual <- function(state_data, state_col="state", color_col="color",
text_color="black", font_size=3,
state_border_col="white", labels=NULL,
legend_title="Legend", legend_position="top",
plot_title="", title_position="bottom") {
if (!title_position %in% c("", "top", "bottom")) {
stop("'title_position' must be either blank, 'top' or 'bottom'")
}
state_data <- data.frame(state_data, stringsAsFactors=FALSE)
if (max(nchar(state_data[,state_col])) == 2) {
merge.x <- "abbrev"
} else {
merge.x <- "state"
}
state_data <- validate_states(state_data, state_col, merge.x)
st.dat <- merge(state_coords, state_data, by.x=merge.x, by.y=state_col, all.y=TRUE)
gg <- ggplot(st.dat, aes_string(x="col", y="row", label="abbrev"))
gg <- gg + geom_tile(aes_string(fill=color_col))
gg <- gg + geom_tile(color=state_border_col, aes_string(fill="color"),
size=2, show.legend=FALSE)
gg <- gg + geom_text(color=text_color, size=font_size)
gg <- gg + scale_y_reverse()
if (is.null(labels)) {
gg <- gg + scale_fill_manual(values=unique(st.dat[,color_col]))
legend_position = "none"
} else {
gg <- gg + scale_fill_manual(values=unique(st.dat[,color_col]),
labels=labels, name=legend_title)
}
gg <- gg + coord_equal()
gg <- gg + labs(x=NULL, y=NULL, title=NULL)
gg <- gg + theme_bw()
gg <- gg + theme(legend.position=legend_position)
gg <- gg + theme(panel.border=element_blank())
gg <- gg + theme(panel.grid=element_blank())
gg <- gg + theme(panel.background=element_blank())
gg <- gg + theme(axis.ticks=element_blank())
gg <- gg + theme(axis.text=element_blank())
if (plot_title != "") {
if (title_position == "bottom") {
gg <- gg + labs(x=plot_title)
gg <- gg + theme(axis.text.x=element_text(hjust=0.5, size=ggplot2::rel(1.2), angle=0))
} else {
gg <- gg + ggtitle(plot_title)
}
}
return(gg)
}

5
R/statebins-package.R

@ -4,12 +4,11 @@
#' @name statebins-package #' @name statebins-package
#' @docType package #' @docType package
#' @author Bob Rudis (bob@@rud.is) #' @author Bob Rudis (bob@@rud.is)
#' @import RColorBrewer viridis
#' @importFrom scales alpha #' @importFrom scales alpha
#' @importFrom ggplot2 ggplot geom_tile scale_fill_manual guides geom_tile ggplotGrob #' @importFrom ggplot2 ggplot geom_tile scale_fill_manual guides geom_tile ggplotGrob
#' @importFrom ggplot2 geom_point geom_text scale_color_manual guides theme labs #' @importFrom ggplot2 geom_point geom_text scale_color_manual guides theme labs
#' @importFrom ggplot2 scale_x_continuous scale_y_continuous coord_equal theme_bw #' @importFrom ggplot2 scale_x_continuous scale_y_continuous coord_equal theme_bw
#' @importFrom ggplot2 aes guide_legend element_rect element_blank element_text #' @importFrom ggplot2 aes element_rect element_blank element_text
#' @importFrom ggplot2 aes_string scale_y_reverse scale_fill_gradientn #' @importFrom ggplot2 aes_string aes_
#' @importFrom ggplot2 scale_fill_brewer ggtitle rel #' @importFrom ggplot2 scale_fill_brewer ggtitle rel
NULL NULL

140
R/statebins.R

@ -1,82 +1,52 @@
#' Create a new ggplot-based "statebin" chart for USA states (discrete scale) #' Create a new ggplot-based "statebin" chart for USA states/territories
#' #'
#' \code{statebins()} creates "statebin" charts in the style of \url{http://bit.ly/statebins} #' Pass in a data frame and get back a square choropleth.
#' #'
#' This version uses discrete \code{RColorBrewer} scales, binned by the "breaks" parameter. #' The `state_col` and `value_col` parameters default to `state` and `value`. That means
#' if you name the columns you want to plot with those names, you can forego passing them
#' in. Othersise, use `"strings"`.
#' #'
#' The function minimally expects the caller to pass in a data frame that: #' A _handy_ feature of this function is that you can specify a `dark_label` color
#' and a `light_label` color. What does that mean? Well, you also pass in the
#' color scale function you're going to use and `statebins` will apply it and use
#' that information to determine what the tile color is and --- if it's "dark" it will
#' use the `light_label` and if it's "light" it will use the `dark_label` color. That
#' means the labels will never blend in to the background (as long as you specify
#' decent label colors).
#' #'
#' \itemize{ #' You can customize the scale function you pass in by using name parameters. All named
#' \item has one column of all state abbreviationis (all caps, including \code{DC} & #' parameters not used by `statebins()` itself get passed to the scale function.
#' \code{PR} or a column of state names (standard capitalization) named \code{state}
#' \item has another column of values named \code{value}
#' }
#'
#' Doing so will create a "statebin" chart with 5 breaks and return a ggplot2 object.
#'
#' You can use a different column for the state names and values by changing \code{state_col}
#' and \code{value_col} accordingly.
#'
#' To add a title, change \code{plot_title} to anything but an empty atomic string vector (i.e. \code{""})
#' and set \code{title_position} to "\code{top}" or "\code{bottom}". Choosing "\code{bottom}"
#' will cause \code{statebins} to use the X axis title as the title.
#' #'
#' @md
#' @param state_data data frame of states and values to plot #' @param state_data data frame of states and values to plot
#' @param state_col column name in \code{state_data} that has the states. no duplicates #' @param state_col column name in \code{state_data} that has the states. no duplicates
#' and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}") #' and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}")
#' @param value_col column name in \code{state_data} that holds the values to be plotted #' @param value_col column name in \code{state_data} that holds the values to be plotted
#' @param text_color default "\code{black}". Size 1 for global color across all tiles or #' @param dark_label,light_label dark/light label colors. The specified color will be used
#' a vector of colors the same length as the number of states you passed in. #' when the algorithm determines labels should be inverted.
#' Use the sort order for the states as they are sorted before being plotted.
#' @param font_size font size (default = \code{3}) #' @param font_size font size (default = \code{3})
#' @param state_border_col default "\code{white}" - this creates the "spaces" between boxes #' @param state_border_col default "\code{white}" - this creates the "spaces" between boxes
#' @param breaks a single number (greater than or equal to 2) giving the number of intervals #' @param state_border_size border size
#' into which data values are to be cut. #' @param ggplot2_scale_function ggplot2 scale function to use. Defaults to `scale_fill_distiller`
#' @param labels labels for the levels \code{breaks} #' since you're likely passing in continuous data when you shouldn't be :-)
#' @param legend_title title for the legend #' @return ggplot2 object
#' @param legend_position "\code{none}", "\code{top}", "\code{left}", "\code{right}" or
#' "\code{bottom}" (defaults to "\code{top}")
#' @param palette either "`brewer`" or "`viridis`". Choose `viridis` if you have
#' 10 or more levels (more than 10 is not recommended). You can choose which
#' viridis palette option (e.g. "magma") with `viridis_pal`.
#' @param brewer_pal which named \code{RColorBrewer} palette to use (defaults to "PuBu");
#' used when `palette` is `brewer`.
#' @param viridis_pal which named \code{viridis} palette option to use (default if `NULL`);
#' used when `palette` is `viridis`.
#' @param plot_title title for the plot
#' @param title_position where to put the title ("\code{bottom}" or "\code{top}" or ""
#' for none); if "\code{bottom}", you get back a grob vs a ggplot object
#' @return ggplot2 object or grob
#' @export #' @export
#' @examples #' @examples
#' \dontrun{
#' data(USArrests) #' data(USArrests)
#'
#' USArrests$state <- rownames(USArrests) #' USArrests$state <- rownames(USArrests)
#' statebins(USArrests, value_col="Assault", text_color="black", font_size=3, #' statebins(USArrests, value_col="Assault", name = "Assault") +
#' legend_title = "Assault", legend_position="bottom") #' theme_statebins(legend_position="right")
#' } statebins <- function(state_data,
statebins <- function(state_data, state_col="state", value_col="value", state_col="state", value_col="value",
text_color="black", font_size=3, dark_label = "black", light_label = "white", font_size=3,
state_border_col="white", state_border_col="white", state_border_size=2,
breaks=5, labels=1:5, ggplot2_scale_function=ggplot2::scale_fill_distiller,
legend_title="Legend", legend_position="top", ...) {
palette=c("brewer", "viridis"), viridis_pal=NULL,
brewer_pal="palette",
plot_title="", title_position="bottom") {
palette <- match.arg(trimws(tolower(palette)), c("brewer", "viridis"))
# if (breaks <= 0 | breaks > 10) {
# stop("'breaks' must be between 0 & 10")
# }
if (!title_position %in% c("", "top", "bottom")) {
stop("'title_position' must be either blank, 'top' or 'bottom'")
}
state_data <- data.frame(state_data, stringsAsFactors=FALSE) state_data <- data.frame(state_data, stringsAsFactors=FALSE)
if (max(nchar(state_data[,state_col])) == 2) { if (max(nchar(state_data[,state_col])) <= 3) {
merge.x <- "abbrev" merge.x <- "abbrev"
} else { } else {
merge.x <- "state" merge.x <- "state"
@ -84,45 +54,25 @@ statebins <- function(state_data, state_col="state", value_col="value",
state_data <- validate_states(state_data, state_col, merge.x) state_data <- validate_states(state_data, state_col, merge.x)
st.dat <- merge(state_coords, state_data, by.x=merge.x, by.y=state_col, all.y=TRUE) st.dat <- merge(state_coords, state_data, by.x=merge.x, by.y=state_col, all.y=TRUE,
sort=TRUE)
st.dat$fill_color <- cut(st.dat[, value_col], breaks=breaks, labels=labels)
gg <- ggplot(st.dat, aes_string(x="col", y="row", label="abbrev")) gg <- ggplot()
gg <- gg + geom_tile(aes_string(fill="fill_color")) gg <- gg + geom_tile(data = st.dat,
gg <- gg + geom_tile(color=state_border_col, aes_string(fill="fill_color"), aes_string(x = "col", y = "row", fill = value_col),
size=2, show.legend=FALSE) color = state_border_col, size = state_border_size)
gg <- gg + geom_text(color=text_color, size=font_size)
gg <- gg + scale_y_reverse() gg <- gg + scale_y_reverse()
gg <- gg + ggplot2_scale_function(...)
if (palette == "brewer") {
gg <- gg + scale_fill_brewer(palette=brewer_pal, name=legend_title, drop=FALSE)
} else if (palette == "viridis") {
if (is.null(viridis_pal)) viridis_pal <- "D"
gg <- gg + scale_fill_viridis(discrete=TRUE, option=viridis_pal, name=legend_title, drop=FALSE)
}
gg <- gg + coord_equal() gg <- gg + coord_equal()
gg <- gg + labs(x=NULL, y=NULL, title=NULL) gg <- gg + labs(x = NULL, y = NULL)
gg <- gg + theme_bw()
gg <- gg + theme(legend.position=legend_position)
gg <- gg + theme(panel.border=element_blank())
gg <- gg + theme(panel.grid=element_blank())
gg <- gg + theme(panel.background=element_blank())
gg <- gg + theme(axis.ticks=element_blank())
gg <- gg + theme(axis.text=element_blank())
if (plot_title != "") {
if (title_position == "bottom") { gb <- ggplot2::ggplot_build(gg)
gg <- gg + labs(x=plot_title)
gg <- gg + theme(axis.text.x=element_text(hjust=0.5, size=ggplot2::rel(1.2), angle=0))
} else {
gg <- gg + ggtitle(plot_title)
}
} gg <- gg + geom_text(data = st.dat,
aes_string(x = "col", y = "row", label = "abbrev"),
color = .sb_invert(gb$data[[1]]$fill, dark_label, light_label),
size = font_size)
return(gg) gg
} }

24
R/theme-statebin.R

@ -0,0 +1,24 @@
#' Base statebins theme
#'
#' Clears out most of the cruft. Builds off of `theme_bw()`
#'
#' @md
#' @param legend_position fills in `legend.position`
#' @param base_family,base_size,base_line_size,base_rect_size same as `theme_bw()`
#' @export
theme_statebins <- function(legend_position="bottom",
base_size = 11, base_family = "",
base_line_size = base_size/22,
base_rect_size = base_size/22) {
gg <- theme_bw(base_family = base_family, base_size = base_size,
base_line_size = base_line_size, base_rect_size = base_rect_size)
gg <- gg + theme(panel.border=element_blank())
gg <- gg + theme(panel.grid=element_blank())
gg <- gg + theme(panel.background=element_blank())
gg <- gg + theme(axis.ticks=element_blank())
gg <- gg + theme(axis.text=element_blank())
gg <- gg + theme(plot.title=element_text(hjust=0.5))
gg <- gg + theme(axis.title.x=element_text(hjust=0.5))
gg <- gg + theme(legend.position=legend_position)
gg
}

12
R/util.R

@ -1,14 +1,14 @@
invert <- function(hexColor, darkColor="black", lightColor="white") { .sb_invert <- function(hex_color, dark_color="black", light_color="white") {
hexColor <- gsub("#", "", hexColor) hex_color <- gsub("#", "", hex_color)
R <- as.integer(paste("0x", substr(hexColor,1,2), sep="")) R <- as.integer(paste("0x", substr(hex_color,1,2), sep=""))
G <- as.integer(paste("0x", substr(hexColor,3,4), sep="")) G <- as.integer(paste("0x", substr(hex_color,3,4), sep=""))
B <- as.integer(paste("0x", substr(hexColor,5,6), sep="")) B <- as.integer(paste("0x", substr(hex_color,5,6), sep=""))
YIQ <- ((R*299) + (G*587) + (B*114)) / 1000 YIQ <- ((R*299) + (G*587) + (B*114)) / 1000
return(ifelse(YIQ >= 128, darkColor, lightColor)) return(ifelse(YIQ >= 128, dark_color, light_color))
} }

236
README.Rmd

@ -1,5 +1,7 @@
--- ---
output: rmarkdown::github_document output: rmarkdown::github_document
editor_options:
chunk_output_type: console
--- ---
```{r echo=FALSE, message=FALSE, warning=FALSE, error=FALSE, include=FALSE} ```{r echo=FALSE, message=FALSE, warning=FALSE, error=FALSE, include=FALSE}
knitr::opts_chunk$set(message=FALSE, warning=FALSE, fig.retina=2) knitr::opts_chunk$set(message=FALSE, warning=FALSE, fig.retina=2)
@ -14,14 +16,8 @@ Create 'U.S.' Uniform Square State Cartogram Heatmaps
The following functions are implemented: The following functions are implemented:
- `statebins` - creates "statebin" charts in the style of http://bit.ly/statebins - This version uses discrete `RColorBrewer` scales, binned by the "breaks" parameter. - `statebins`: Creates "statebin" charts in the style of http://bit.ly/statebins
- `statebins_continuous` - creates "statebin" charts in the style of http://bit.ly/statebins - This version uses a continuous scale based on `RColorBrewer` scales (passing in a 6 element `RColorBrewer` palette to `scale_fill_gradientn`). - `theme_statebins`: Base statebins theme
- `statebins_manual` - creates "statebin" charts using manually specified colors in a column
## TODO
- The current version is usable, but I think the plot margins and the legends need work
- Apply algorithm to switch to light-on-dark depending on the background tile color
## Installation ## Installation
@ -41,182 +37,94 @@ library(tidyverse)
packageVersion("statebins") packageVersion("statebins")
# the original wapo data # the original wapo data
cols(
fipst = col_character(), stab = col_character(), state = col_character(), workers1994 = col_integer(), workers1995 = col_integer(), workers1996 = col_integer(), workers1997 = col_integer(), workers1998 = col_integer(), workers1999 = col_integer(), workers2000 = col_integer(), workers2001 = col_integer(), workers2002 = col_integer(), workers2003 = col_integer(), workers2004 = col_integer(), workers2005 = col_integer(), workers2006 = col_integer(), workers2007 = col_integer(), workers2008 = col_integer(), workers2009 = col_integer(), workers2010 = col_integer(), workers2011 = col_integer(), workers2012 = col_integer(), workers2013 = col_integer(), adat <- suppressMessages(read_csv("http://www.washingtonpost.com/wp-srv/special/business/states-most-threatened-by-trade/states.csv?cache=1"))
share_cut1994 = col_double(), share_cut1995 = col_double(), share_cut1996 = col_double(), share_cut1997 = col_double(), share_cut1998 = col_double(), share_cut1999 = col_double(), share_cut2000 = col_double(), share_cut2001 = col_double(), share_cut2002 = col_double(), share_cut2003 = col_double(), share_cut2004 = col_double(), share_cut2005 = col_double(), share_cut2006 = col_double(), share_cut2007 = col_double(), share_cut2008 = col_double(), share_cut2009 = col_double(), share_cut2010 = col_double(), share_cut2011 = col_double(), share_cut2012 = col_double(), share_cut2013 = col_double(),
avgshare = col_double(), avgshare94_00 = col_double(), avgshare01_07 = col_double(), avgshare08_12 = col_double() mutate(
) -> wapo_cols adat,
share = cut(avgshare94_00, breaks = 4, labels = c("0-1", "1-2", "2-3", "3-4"))
adat <- read_csv("http://www.washingtonpost.com/wp-srv/special/business/states-most-threatened-by-trade/states.csv?cache=1", ) %>%
col_types = wapo_cols) statebins(
value_col = "share",
gg <- statebins( ggplot2_scale_function = scale_fill_brewer,
adat, "state", "avgshare94_00", name = "Share of workforce with jobs lost or threatened by trade"
breaks = 4, ) +
labels = c("0-1", "1-2", "2-3", "3-4"), labs(title = "1994-2000") +
legend_title = "Share of workforce with jobs lost or threatened by trade", theme_statebins()
font_size = 3,
brewer_pal = "Blues",
text_color = "black",
plot_title = "1994-2000",
title_position = "bottom"
)
gg
# continuous scale, legend on top # continuous scale, legend on top
gg2 <- statebins_continuous( statebins(
adat, "state", "avgshare01_07", adat, value_col = "avgshare01_07",
legend_title="Share of workforce with jobs lost or threatened by trade", legend_position="top", name = "Share of workforce with jobs lost or threatened by trade",
brewer_pal="OrRd", text_color="black", font_size=3, palette = "OrRd", direction = 1
plot_title="2001-2007", title_position="bottom" ) +
) labs(x="2001-2007") +
theme_statebins(legend_position="top")
gg2
# continuous scale, no legend # continuous scale, no legend
gg3 <- statebins_continuous( statebins(adat, value_col = "avgshare08_12", palette = "Purples") +
adat, "state", "avgshare08_12", labs(x="2008-2010") +
legend_title="States", legend_position="none", theme_statebins(legend_position = "none")
brewer_pal="Purples", text_color="black", font_size=3,
plot_title="2008-2012", title_position="bottom"
)
gg3
# mortality (only to show PR and using a data.table) # mortality data (has Puerto Rico)
# from: http://www.cdc.gov/nchs/fastats/state-and-territorial-data.htm # from: http://www.cdc.gov/nchs/fastats/state-and-territorial-data.htm
cols( dat <- suppressMessages(read_csv("http://datadrivensecurity.info/data/deaths.csv"))
state = col_character(),
births = col_integer(),
fertility_rate = col_double(),
deaths = col_integer(),
death_rate = col_double()
) -> deaths_cols
dat <- read_csv("http://datadrivensecurity.info/data/deaths.csv", col_types=deaths_cols) statebins(dat, value_col = "death_rate", name="Per 100K pop") +
statebins_continuous(dat, "state", "death_rate", legend_title="Per 100K pop", labs(title="Mortality Rate (2010)") +
plot_title="Mortality Rate (2010)") theme_statebins()
# fertility (only to show tbl_dt) # fertility data
statebins_continuous(dat, "state", "fertility_rate", legend_title="Per 100K pop", statebins(dat, value_col="fertility_rate", name="Per 100K pop", palette="PuBuGn") +
plot_title="Fertility Rate (2010)", brewer_pal="PuBuGn") labs(title="Fertility Rate (2010)") +
theme_statebins()
# manual - perhaps good for elections? # manual - perhaps good for elections?
library(httr) election_2012 <- suppressMessages(read_csv("https://raw.githubusercontent.com/hrbrmstr/statebins/master/tmp/election2012.csv"))
library(dplyr)
election_2012 <- GET("https://raw.githubusercontent.com/hrbrmstr/statebins/master/tmp/election2012.csv")
read.csv(
textConnection(content(election_2012, as="text")),
header=TRUE, stringsAsFactors=FALSE
) %>%
mutate(color=ifelse(is.na(Obama), "#2166ac", "#b2182b")) %>%
select(state, color) -> results
statebins_manual(
results,
font_size=4, text_color = "white",
labels=c("Romney", "Obama"), legend_position="right", legend_title="Winner"
)
# or, more like the one in the WaPo article; i might be picking the wrong columns here. it's just for an example mutate(election_2012, value = ifelse(is.na(Obama), "Romney", "Obama")) %>%
sb <- function(col, title) {
statebins( statebins(
adat, "state", col, brewer_pal="Blues", text_color="black", font_size=4, dark_label = "white", light_label = "white",
legend_position="none", font_size=3, plot_title=title, ggplot2_scale_function = scale_fill_manual,
breaks=4, labels=1:4 name = "Winner",
) values = c(Romney = "#2166ac", Obama = "#b2182b")
} ) +
``` theme_statebins()
```{r eval=FALSE}
# cheating and using <table> to arrange them below and also making a WaPo-like legend,
# since mucking with grid graphics margins/padding was not an option time-wise at the moment
sb("avgshare94_00", "1994-2000")
sb("avgshare01_07", "2001-2007")
sb("avgshare08_12", "2008-2012")
``` ```
<!-- uncomment the following and add backticks where appropriate and remove the reference to --> ### All the "states"
<!-- the static image when the rmarkdown output is HTML and this will work fine. github does not render the markdown properly -->
<!--
<span style="font-size:17px; color:#333;">Share of workforce with jobs lost or threatened by trade</span><br/>
<table style="width:200px" cellpadding=0, cellspacing=0><tr style="line-height:10px">
<td width="25%" style="background:#EFF3FF;">&nbsp;</td>
<td width="25%" style="background:#BDD7E7;">&nbsp;</td>
<td width="25%" style="background:#6BAED6;">&nbsp;</td>
<td width="25%" style="background:#2171B5;">&nbsp;</td></tr>
<tr><td colspan=2 align="left" style="font-size:14px">Smallest share</td><td colspan=2 align="right" style="font-size:14px">Largest</td></tr>
</table>
<table width="100%" cellpadding="0" cellspacing="0"> `statebins` now has PR, VI & NYC (by name or abbreviation) so you can use them, too:
<tr><td width="50%">
{r f1994, echo=FALSE, fig.width=6, fig.height=5} ```{r}
sb("avgshare94_00", "1994-2000") library(statebins)
library(tidyverse)
</td><td width="50%"> library(viridis)
{r f2001, echo=FALSE, fig.width=6, fig.height=5, results='asis'} data(USArrests)
sb("avgshare01_07", "2001-2007")
# make up some data for the example
</td></tr><tr><td width="50%">
rownames_to_column(USArrests, "state") %>%
{r f2008, echo=FALSE, fig.width=6, fig.height=5, results='asis'} bind_rows(
sb("avgshare08_12", "2008-2012") data_frame(
state = c("Virgin Islands", "Puerto Rico", "New York City"),
</td><td width="50%"> &nbsp; </td></tr></table> Murder = rep(mean(max(USArrests$Murder),3)),
Assault = rep(mean(max(USArrests$Assault),3)),
--> Rape = rep(mean(max(USArrests$Rape),3)),
UrbanPop = c(93, 95, 100)
<center>![img](./tmp/statebins-composite.png)</center> )
) -> us_arrests
And, we'll throw in a gratuitous animation for good measure:
statebins(us_arrests, value_col="Assault",
```{r eval=FALSE} ggplot2_scale_function = viridis::scale_fill_viridis) +
library(magick) labs(title="USArrests + made up data") +
# data set from StatsAmerica - http://www.statsamerica.org/profiles/sip_index.html theme_statebins("right")
```
# median household income from the ACS survey
miacs <- read.csv("http://datadrivensecurity.info/data/median-income-acs.csv",
header=TRUE, stringsAsFactors=FALSE)
# generate frames based on year
purrr::map(unique(miacs$year), function(year) {
cat(".")
fig <- magick::image_graph(res=144)
rng <- floor(range(miacs[miacs$year==year,]$mh_inc))
statebins(
miacs[miacs$year==year,], "state", "mh_inc",
legend_title="States", legend_position="none",
brewer_pal="Greens", text_color="black", font_size=3,
plot_title=sprintf("Median Household Income (ACS) %d\n$%s - $%s", year,
scales::comma(rng[1]), scales::comma(rng[2])),
title_position="top"
) -> ggtmp
print(ggtmp)
dev.off()
fig
}) %>% image_join() %>%
image_animate(fps=2, loop=1)
```
<center>![img](./tmp/household.gif)</embed></center>

BIN
README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

BIN
README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

BIN
README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

BIN
README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

BIN
README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

BIN
README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-6.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

268
README.md

@ -7,22 +7,9 @@ Create ‘U.S.’ Uniform Square State Cartogram Heatmaps
The following functions are implemented: The following functions are implemented:
- `statebins` - creates “statebin” charts in the style of - `statebins`: Creates “statebin” charts in the style of
<http://bit.ly/statebins> - This version uses discrete <http://bit.ly/statebins>
`RColorBrewer` scales, binned by the “breaks” parameter. - `theme_statebins`: Base statebins theme
- `statebins_continuous` - creates “statebin” charts in the style of
<http://bit.ly/statebins> - This version uses a continuous scale
based on `RColorBrewer` scales (passing in a 6 element
`RColorBrewer` palette to `scale_fill_gradientn`).
- `statebins_manual` - creates “statebin” charts using manually
specified colors in a column
## TODO
- The current version is usable, but I think the plot margins and the
legends need work
- Apply algorithm to switch to light-on-dark depending on the
background tile color
## Installation ## Installation
@ -50,216 +37,117 @@ packageVersion("statebins")
``` r ``` r
# the original wapo data # the original wapo data
cols(
fipst = col_character(), stab = col_character(), state = col_character(), workers1994 = col_integer(), workers1995 = col_integer(), workers1996 = col_integer(), workers1997 = col_integer(), workers1998 = col_integer(), workers1999 = col_integer(), workers2000 = col_integer(), workers2001 = col_integer(), workers2002 = col_integer(), workers2003 = col_integer(), workers2004 = col_integer(), workers2005 = col_integer(), workers2006 = col_integer(), workers2007 = col_integer(), workers2008 = col_integer(), workers2009 = col_integer(), workers2010 = col_integer(), workers2011 = col_integer(), workers2012 = col_integer(), workers2013 = col_integer(), adat <- suppressMessages(read_csv("http://www.washingtonpost.com/wp-srv/special/business/states-most-threatened-by-trade/states.csv?cache=1"))
share_cut1994 = col_double(), share_cut1995 = col_double(), share_cut1996 = col_double(), share_cut1997 = col_double(), share_cut1998 = col_double(), share_cut1999 = col_double(), share_cut2000 = col_double(), share_cut2001 = col_double(), share_cut2002 = col_double(), share_cut2003 = col_double(), share_cut2004 = col_double(), share_cut2005 = col_double(), share_cut2006 = col_double(), share_cut2007 = col_double(), share_cut2008 = col_double(), share_cut2009 = col_double(), share_cut2010 = col_double(), share_cut2011 = col_double(), share_cut2012 = col_double(), share_cut2013 = col_double(),
avgshare = col_double(), avgshare94_00 = col_double(), avgshare01_07 = col_double(), avgshare08_12 = col_double() mutate(
) -> wapo_cols adat,
share = cut(avgshare94_00, breaks = 4, labels = c("0-1", "1-2", "2-3", "3-4"))
adat <- read_csv("http://www.washingtonpost.com/wp-srv/special/business/states-most-threatened-by-trade/states.csv?cache=1", ) %>%
col_types = wapo_cols) statebins(
value_col = "share",
gg <- statebins( ggplot2_scale_function = scale_fill_brewer,
adat, "state", "avgshare94_00", name = "Share of workforce with jobs lost or threatened by trade"
breaks = 4, ) +
labels = c("0-1", "1-2", "2-3", "3-4"), labs(title = "1994-2000") +
legend_title = "Share of workforce with jobs lost or threatened by trade", theme_statebins()
font_size = 3,
brewer_pal = "Blues",
text_color = "black",
plot_title = "1994-2000",
title_position = "bottom"
)
gg
``` ```
<img src="README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-1.png" width="672" /> <img src="README_files/figure-gfm/unnamed-chunk-3-1.png" width="672" />
``` r ``` r
# continuous scale, legend on top # continuous scale, legend on top
gg2 <- statebins_continuous( statebins(
adat, "state", "avgshare01_07", adat, value_col = "avgshare01_07",
legend_title="Share of workforce with jobs lost or threatened by trade", legend_position="top", name = "Share of workforce with jobs lost or threatened by trade",
brewer_pal="OrRd", text_color="black", font_size=3, palette = "OrRd", direction = 1
plot_title="2001-2007", title_position="bottom" ) +
) labs(x="2001-2007") +
theme_statebins(legend_position="top")
gg2
``` ```
<img src="README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-2.png" width="672" /> <img src="README_files/figure-gfm/unnamed-chunk-3-2.png" width="672" />
``` r ``` r
# continuous scale, no legend # continuous scale, no legend
gg3 <- statebins_continuous( statebins(adat, value_col = "avgshare08_12", palette = "Purples") +
adat, "state", "avgshare08_12", labs(x="2008-2010") +
legend_title="States", legend_position="none", theme_statebins(legend_position = "none")
brewer_pal="Purples", text_color="black", font_size=3,
plot_title="2008-2012", title_position="bottom"
)
gg3
``` ```
<img src="README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-3.png" width="672" /> <img src="README_files/figure-gfm/unnamed-chunk-3-3.png" width="672" />
``` r ``` r
# mortality (only to show PR and using a data.table) # mortality data (has Puerto Rico)
# from: http://www.cdc.gov/nchs/fastats/state-and-territorial-data.htm # from: http://www.cdc.gov/nchs/fastats/state-and-territorial-data.htm
cols( dat <- suppressMessages(read_csv("http://datadrivensecurity.info/data/deaths.csv"))
state = col_character(),
births = col_integer(), statebins(dat, value_col = "death_rate", name="Per 100K pop") +
fertility_rate = col_double(), labs(title="Mortality Rate (2010)") +
deaths = col_integer(), theme_statebins()
death_rate = col_double()
) -> deaths_cols
dat <- read_csv("http://datadrivensecurity.info/data/deaths.csv", col_types=deaths_cols)
statebins_continuous(dat, "state", "death_rate", legend_title="Per 100K pop",
plot_title="Mortality Rate (2010)")
``` ```
<img src="README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-4.png" width="672" /> <img src="README_files/figure-gfm/unnamed-chunk-3-4.png" width="672" />
``` r ``` r
# fertility (only to show tbl_dt) # fertility data
statebins_continuous(dat, "state", "fertility_rate", legend_title="Per 100K pop", statebins(dat, value_col="fertility_rate", name="Per 100K pop", palette="PuBuGn") +
plot_title="Fertility Rate (2010)", brewer_pal="PuBuGn") labs(title="Fertility Rate (2010)") +
theme_statebins()
``` ```
<img src="README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-5.png" width="672" /> <img src="README_files/figure-gfm/unnamed-chunk-3-5.png" width="672" />
``` r ``` r
# manual - perhaps good for elections? # manual - perhaps good for elections?
library(httr) election_2012 <- suppressMessages(read_csv("https://raw.githubusercontent.com/hrbrmstr/statebins/master/tmp/election2012.csv"))
library(dplyr)
election_2012 <- GET("https://raw.githubusercontent.com/hrbrmstr/statebins/master/tmp/election2012.csv")
read.csv(
textConnection(content(election_2012, as="text")),
header=TRUE, stringsAsFactors=FALSE
) %>%
mutate(color=ifelse(is.na(Obama), "#2166ac", "#b2182b")) %>%
select(state, color) -> results
statebins_manual(
results,
font_size=4, text_color = "white",
labels=c("Romney", "Obama"), legend_position="right", legend_title="Winner"
)
```
<img src="README.gfm-ascii_identifiers_files/figure-gfm/unnamed-chunk-3-6.png" width="672" />
``` r
# or, more like the one in the WaPo article; i might be picking the wrong columns here. it's just for an example
sb <- function(col, title) { mutate(election_2012, value = ifelse(is.na(Obama), "Romney", "Obama")) %>%
statebins( statebins(
adat, "state", col, brewer_pal="Blues", text_color="black", font_size=4, dark_label = "white", light_label = "white",
legend_position="none", font_size=3, plot_title=title, ggplot2_scale_function = scale_fill_manual,
breaks=4, labels=1:4 name = "Winner",
) values = c(Romney = "#2166ac", Obama = "#b2182b")
} ) +
``` theme_statebins()
``` r
# cheating and using <table> to arrange them below and also making a WaPo-like legend,
# since mucking with grid graphics margins/padding was not an option time-wise at the moment
sb("avgshare94_00", "1994-2000")
sb("avgshare01_07", "2001-2007")
sb("avgshare08_12", "2008-2012")
``` ```
<!-- uncomment the following and add backticks where appropriate and remove the reference to --> <img src="README_files/figure-gfm/unnamed-chunk-3-6.png" width="672" />
<!-- the static image when the rmarkdown output is HTML and this will work fine. github does not render the markdown properly --> ### All the “states”
<!-- `statebins` now has PR, VI & NYC (by name or abbreviation) so you can
<span style="font-size:17px; color:#333;">Share of workforce with jobs lost or threatened by trade</span><br/> use them, too:
<table style="width:200px" cellpadding=0, cellspacing=0><tr style="line-height:10px">
<td width="25%" style="background:#EFF3FF;">&nbsp;</td>
<td width="25%" style="background:#BDD7E7;">&nbsp;</td>
<td width="25%" style="background:#6BAED6;">&nbsp;</td>
<td width="25%" style="background:#2171B5;">&nbsp;</td></tr>
<tr><td colspan=2 align="left" style="font-size:14px">Smallest share</td><td colspan=2 align="right" style="font-size:14px">Largest</td></tr>
</table>
<table width="100%" cellpadding="0" cellspacing="0">
<tr><td width="50%">
{r f1994, echo=FALSE, fig.width=6, fig.height=5}
sb("avgshare94_00", "1994-2000")
</td><td width="50%">
{r f2001, echo=FALSE, fig.width=6, fig.height=5, results='asis'}
sb("avgshare01_07", "2001-2007")
</td></tr><tr><td width="50%">
{r f2008, echo=FALSE, fig.width=6, fig.height=5, results='asis'}
sb("avgshare08_12", "2008-2012")
</td><td width="50%"> &nbsp; </td></tr></table>
-->
<center>
![img](./tmp/statebins-composite.png)
</center>
And, we’ll throw in a gratuitous animation for good measure:
``` r ``` r
library(magick) library(statebins)
# data set from StatsAmerica - http://www.statsamerica.org/profiles/sip_index.html library(tidyverse)
library(viridis)
# median household income from the ACS survey
miacs <- read.csv("http://datadrivensecurity.info/data/median-income-acs.csv", data(USArrests)
header=TRUE, stringsAsFactors=FALSE)
# make up some data for the example
# generate frames based on year
purrr::map(unique(miacs$year), function(year) { rownames_to_column(USArrests, "state") %>%
bind_rows(
cat(".") data_frame(
state = c("Virgin Islands", "Puerto Rico", "New York City"),
fig <- magick::image_graph(res=144) Murder = rep(mean(max(USArrests$Murder),3)),
Assault = rep(mean(max(USArrests$Assault),3)),
rng <- floor(range(miacs[miacs$year==year,]$mh_inc)) Rape = rep(mean(max(USArrests$Rape),3)),
UrbanPop = c(93, 95, 100)
statebins( )
miacs[miacs$year==year,], "state", "mh_inc", ) -> us_arrests
legend_title="States", legend_position="none",
brewer_pal="Greens", text_color="black", font_size=3, statebins(us_arrests, value_col="Assault",
plot_title=sprintf("Median Household Income (ACS) %d\n$%s - $%s", year, ggplot2_scale_function = viridis::scale_fill_viridis) +
scales::comma(rng[1]), scales::comma(rng[2])), labs(title="USArrests + made up data") +
title_position="top" theme_statebins("right")
) -> ggtmp
print(ggtmp)
dev.off()
fig
}) %>% image_join() %>%
image_animate(fps=2, loop=1)
``` ```
<center> <img src="README_files/figure-gfm/unnamed-chunk-4-1.png" width="672" />
![img](./tmp/household.gif)</embed>
</center>

BIN
README_files/figure-gfm/unnamed-chunk-3-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
README_files/figure-gfm/unnamed-chunk-3-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
README_files/figure-gfm/unnamed-chunk-3-3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
README_files/figure-gfm/unnamed-chunk-3-4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
README_files/figure-gfm/unnamed-chunk-3-5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
README_files/figure-gfm/unnamed-chunk-3-6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
README_files/figure-gfm/unnamed-chunk-4-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

80
man/statebins.Rd

@ -2,14 +2,12 @@
% Please edit documentation in R/statebins.R % Please edit documentation in R/statebins.R
\name{statebins} \name{statebins}
\alias{statebins} \alias{statebins}
\title{Create a new ggplot-based "statebin" chart for USA states (discrete scale)} \title{Create a new ggplot-based "statebin" chart for USA states/territories}
\usage{ \usage{
statebins(state_data, state_col = "state", value_col = "value", statebins(state_data, state_col = "state", value_col = "value",
text_color = "black", font_size = 3, state_border_col = "white", dark_label = "black", light_label = "white", font_size = 3,
breaks = 5, labels = 1:5, legend_title = "Legend", state_border_col = "white", state_border_size = 2,
legend_position = "top", palette = c("brewer", "viridis"), ggplot2_scale_function = ggplot2::scale_fill_distiller, ...)
viridis_pal = NULL, brewer_pal = "palette", plot_title = "",
title_position = "bottom")
} }
\arguments{ \arguments{
\item{state_data}{data frame of states and values to plot} \item{state_data}{data frame of states and values to plot}
@ -19,70 +17,44 @@ and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}")}
\item{value_col}{column name in \code{state_data} that holds the values to be plotted} \item{value_col}{column name in \code{state_data} that holds the values to be plotted}
\item{text_color}{default "\code{black}". Size 1 for global color across all tiles or \item{dark_label, light_label}{dark/light label colors. The specified color will be used
a vector of colors the same length as the number of states you passed in. when the algorithm determines labels should be inverted.}
Use the sort order for the states as they are sorted before being plotted.}
\item{font_size}{font size (default = \code{3})} \item{font_size}{font size (default = \code{3})}
\item{state_border_col}{default "\code{white}" - this creates the "spaces" between boxes} \item{state_border_col}{default "\code{white}" - this creates the "spaces" between boxes}
\item{breaks}{a single number (greater than or equal to 2) giving the number of intervals \item{state_border_size}{border size}
into which data values are to be cut.}
\item{labels}{labels for the levels \code{breaks}} \item{ggplot2_scale_function}{ggplot2 scale function to use. Defaults to \code{scale_fill_distiller}
since you're likely passing in continuous data when you shouldn't be :-)}
\item{legend_title}{title for the legend}
\item{legend_position}{"\code{none}", "\code{top}", "\code{left}", "\code{right}" or
"\code{bottom}" (defaults to "\code{top}")}
\item{palette}{either "`brewer`" or "`viridis`". Choose `viridis` if you have
10 or more levels (more than 10 is not recommended). You can choose which
viridis palette option (e.g. "magma") with `viridis_pal`.}
\item{viridis_pal}{which named \code{viridis} palette option to use (default if `NULL`);
used when `palette` is `viridis`.}
\item{brewer_pal}{which named \code{RColorBrewer} palette to use (defaults to "PuBu");
used when `palette` is `brewer`.}
\item{plot_title}{title for the plot}
\item{title_position}{where to put the title ("\code{bottom}" or "\code{top}" or ""
for none); if "\code{bottom}", you get back a grob vs a ggplot object}
} }
\value{ \value{
ggplot2 object or grob ggplot2 object
} }
\description{ \description{
\code{statebins()} creates "statebin" charts in the style of \url{http://bit.ly/statebins} Pass in a data frame and get back a square choropleth.
} }
\details{ \details{
This version uses discrete \code{RColorBrewer} scales, binned by the "breaks" parameter. The \code{state_col} and \code{value_col} parameters default to \code{state} and \code{value}. That means
if you name the columns you want to plot with those names, you can forego passing them
in. Othersise, use \code{"strings"}.
The function minimally expects the caller to pass in a data frame that: A \emph{handy} feature of this function is that you can specify a \code{dark_label} color
and a \code{light_label} color. What does that mean? Well, you also pass in the
color scale function you're going to use and \code{statebins} will apply it and use
that information to determine what the tile color is and --- if it's "dark" it will
use the \code{light_label} and if it's "light" it will use the \code{dark_label} color. That
means the labels will never blend in to the background (as long as you specify
decent label colors).
\itemize{ You can customize the scale function you pass in by using name parameters. All named
\item has one column of all state abbreviationis (all caps, including \code{DC} & parameters not used by \code{statebins()} itself get passed to the scale function.
\code{PR} or a column of state names (standard capitalization) named \code{state}
\item has another column of values named \code{value}
}
Doing so will create a "statebin" chart with 5 breaks and return a ggplot2 object.
You can use a different column for the state names and values by changing \code{state_col}
and \code{value_col} accordingly.
To add a title, change \code{plot_title} to anything but an empty atomic string vector (i.e. \code{""})
and set \code{title_position} to "\code{top}" or "\code{bottom}". Choosing "\code{bottom}"
will cause \code{statebins} to use the X axis title as the title.
} }
\examples{ \examples{
\dontrun{
data(USArrests) data(USArrests)
USArrests$state <- rownames(USArrests) USArrests$state <- rownames(USArrests)
statebins(USArrests, value_col="Assault", text_color="black", font_size=3, statebins(USArrests, value_col="Assault", name = "Assault") +
legend_title = "Assault", legend_position="bottom") theme_statebins(legend_position="right")
}
} }

74
man/statebins_continuous.Rd

@ -1,74 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/statebins-continuous.R
\name{statebins_continuous}
\alias{statebins_continuous}
\title{Create a new ggplot-based "statebin" chart for USA states (continuous scale)}
\usage{
statebins_continuous(state_data, state_col = "state", value_col = "value",
text_color = "black", font_size = 3, state_border_col = "white",
legend_title = "Legend", legend_position = "top", brewer_pal = "PuBu",
plot_title = "", title_position = "bottom")
}
\arguments{
\item{state_data}{data frame of states and values to plot}
\item{state_col}{column name in \code{state_data} that has the states. no duplicates
and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}")}
\item{value_col}{column name in \code{state_data} that holds the values to be plotted}
\item{text_color}{default "\code{black}". Size 1 for global color across all tiles or
a vector of colors the same length as the number of states you passed in.
Use the sort order for the states as they are sorted before being plotted.}
\item{font_size}{font size (default = \code{3})}
\item{state_border_col}{default "\code{white}" - this creates the "spaces" between boxes}
\item{legend_title}{title for the legend}
\item{legend_position}{"\code{none}", "\code{top}", "\code{left}", "\code{right}" or
"\code{bottom}" (defaults to "\code{top}")}
\item{brewer_pal}{which named \code{RColorBrewer} palette to use (defaults to "PuBu")}
\item{plot_title}{title for the plot}
\item{title_position}{where to put the title ("\code{bottom}" or "\code{top}" or ""
for none); if "\code{bottom}", you get back a grob vs a ggplot object}
}
\value{
ggplot2 object or grob
}
\description{
\code{statebins()} creates "statebin" charts in the style of \url{http://bit.ly/statebins}
}
\details{
This version uses a continuous scale based on \code{RColorBrewer} scales
(passing in a 6 element \code{RColorBrewer} palette to \code{scale_fill_gradientn}).
The function minimally expects the caller to pass in a data frame that:
\itemize{
\item has one column of all state abbreviationis (all caps, including \code{DC} &
\code{PR} ) or a column of state names (standard capitalization) named \code{state}
\item has another column of values named \code{value}
}
Doing so will create a "statebin" chart with 5 breaks and return a \code{ggplot2} object.
You can use a different column for the state names and values by changing \code{state_col}
and \code{value_col} accordingly.
To add a title, change \code{plot_title} to anything but an empty atomic string vector (i.e. \code{""})
and set \code{title_position} to "\code{top}" or "\code{bottom}". Choosing "\code{bottom}"
will cause \code{statebins} to use the X axis title placeholder.
}
\examples{
\dontrun{
data(USArrests)
USArrests$state <- rownames(USArrests)
statebins_continuous(USArrests, value_col="Murder", text_color="black", font_size=3,
legend_title = "Murder", legend_position="bottom")
}
}

83
man/statebins_manual.Rd

@ -1,83 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/statebins-manual.R
\name{statebins_manual}
\alias{statebins_manual}
\title{Create a new ggplot-based "statebin" chart for USA states (manually colored)}
\usage{
statebins_manual(state_data, state_col = "state", color_col = "color",
text_color = "black", font_size = 3, state_border_col = "white",
labels = NULL, legend_title = "Legend", legend_position = "top",
plot_title = "", title_position = "bottom")
}
\arguments{
\item{state_data}{data frame of states and values to plot}
\item{state_col}{column name in \code{state_data} that has the states. no duplicates
and can be names (e.g. "\code{Maine}") or abbreviatons (e.g. "\code{ME}")}
\item{color_col}{column name in \code{state_data} that holds the colors to be used}
\item{text_color}{default "\code{black}". Size 1 for global color across all tiles or
a vector of colors the same length as the number of states you passed in.
Use the sort order for the states as they are sorted before being plotted.}
\item{font_size}{font size (default = \code{3})}
\item{state_border_col}{default "\code{white}" - this creates the "spaces" between boxes}
\item{labels}{labels for the legend (should be the same number as distinct colors in
\code{color_col}); \code{NULL} == no labels/legend}
\item{legend_title}{title for the legend}
\item{legend_position}{"\code{none}", "\code{top}", "\code{left}", "\code{right}" or
"\code{bottom}" (defaults to "\code{top}")}
\item{plot_title}{title for the plot}
\item{title_position}{where to put the title ("\code{bottom}" or "\code{top}" or ""
for none); if "\code{bottom}", you get back a grob vs a ggplot object}
}
\value{
ggplot2 object or grob
}
\description{
\code{statebins()} creates "statebin" charts in the style of \url{http://bit.ly/statebins}
}
\details{
This version uses manual colors (i.e. pass in a column that defines the color per-state)
The function minimally expects the caller to pass in a data frame that:
\itemize{
\item has one column of all state abbreviationis (all caps, including \code{DC} &
\code{PR} or a column of state names (standard capitalization) named \code{state}
\item has another column of colors named \code{color}
}
Doing so will create a "statebin" chart with the colors specified as a ggplot2 object.
You can use a different column for the state names and colors by changing \code{state_col}
and \code{color_col} accordingly.
To add a title, change \code{plot_title} to anything but an empty atomic string vector (i.e. \code{""})
and set \code{title_position} to "\code{top}" or "\code{bottom}". Choosing "\code{bottom}"
will cause \code{statebins} to use the X axis title placeholder.
}
\examples{
\dontrun{
library(httr)
library(dplyr)
election_2012 <-
GET("https://raw.githubusercontent.com/hrbrmstr/statebins/master/tmp/election2012.csv")
results <- read.csv(textConnection(content(election_2012, as="text")),
header=TRUE, stringsAsFactors=FALSE)
results <- results \%>\%
mutate(color=ifelse(is.na(Obama), "#2166ac", "#b2182b")) \%>\%
select(state, color)
results \%>\%
statebins_manual(font_size=4,
text_color = "white", labels=c("Romney", "Obama"),
legend_position="right", legend_title="Winner")
}
}

18
man/theme_statebins.Rd

@ -0,0 +1,18 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/theme-statebin.R
\name{theme_statebins}
\alias{theme_statebins}
\title{Base statebins theme}
\usage{
theme_statebins(legend_position = "bottom", base_size = 11,
base_family = "", base_line_size = base_size/22,
base_rect_size = base_size/22)
}
\arguments{
\item{legend_position}{fills in \code{legend.position}}
\item{base_family, base_size, base_line_size, base_rect_size}{same as \code{theme_bw()}}
}
\description{
Clears out most of the cruft. Builds off of \code{theme_bw()}
}

52
tmp/election2012.csv

@ -1,52 +0,0 @@
state,Obama,Romney
AL,,9
AK,,3
AZ,,11
AR,,6
CA,55,
CO,9,
CT,7,
DE,3,
DC,3,
FL,29,
GA,,16
HI,4,
ID,,4
IL,20,
IN,,11
IA,6,
KS,,6
KY,,8
LA,,8
ME,4,
MD,10,
MA,11,
MI,16,
MN,10,
MS,,6
MO,,10
MT,,3
NE,,5
NV,6,
NH,4,
NJ,14,
NM,5,
NY,29,
NC,,15
ND,,3
OH,18,
OK,,7
OR,7,
PA,20,
RI,4,
SC,,9
SD,,3
TN,,11
TX,,38
UT,,6
VT,3,
VA,13,
WA,12,
WV,,5
WI,10,
WY,,3
1 state Obama Romney
2 AL 9
3 AK 3
4 AZ 11
5 AR 6
6 CA 55
7 CO 9
8 CT 7
9 DE 3
10 DC 3
11 FL 29
12 GA 16
13 HI 4
14 ID 4
15 IL 20
16 IN 11
17 IA 6
18 KS 6
19 KY 8
20 LA 8
21 ME 4
22 MD 10
23 MA 11
24 MI 16
25 MN 10
26 MS 6
27 MO 10
28 MT 3
29 NE 5
30 NV 6
31 NH 4
32 NJ 14
33 NM 5
34 NY 29
35 NC 15
36 ND 3
37 OH 18
38 OK 7
39 OR 7
40 PA 20
41 RI 4
42 SC 9
43 SD 3
44 TN 11
45 TX 38
46 UT 6
47 VT 3
48 VA 13
49 WA 12
50 WV 5
51 WI 10
52 WY 3

BIN
tmp/household.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 KiB

BIN
tmp/household2000.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2001.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2002.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2003.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2004.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2005.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2006.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2007.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2008.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2009.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2010.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2011.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/household2012.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
tmp/statebins-composite.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Loading…
Cancel
Save