{"id":20914,"date":"2021-06-15T11:00:51","date_gmt":"2021-06-15T11:00:51","guid":{"rendered":"https:\/\/www.highcharts.com\/blog\/?p=20914"},"modified":"2026-01-13T11:20:29","modified_gmt":"2026-01-13T11:20:29","slug":"using-highcharter-in-tidytuesday-internet-access","status":"publish","type":"post","link":"https:\/\/www.highcharts.com\/blog\/integration\/using-highcharter-in-tidytuesday-internet-access\/","title":{"rendered":"Using Highcharter in Tidytuesday Internet Access"},"content":{"rendered":"<p>Undoubtedly, the pandemic has brought with it a multitude of problems while enhancing the pre-existing ones. Many businesses, schools, or government procedures assimilated a digital model, while a large part of them closed their doors. Accessing those digital models became an almost inaccessible task. Years of unnoticed growth of this problem now stand out clearly. The issue of the broadband gap is now impossible to ignore. ?<\/p>\n<p>You are a curious person. \u2728 Microsoft&#8217;s The Verge designed an article about the bandwidth gap problem in the United States. They generated a map that highlights bivalence between counties that do not have a good internet connection. <\/p>\n<p>In this blog, you will learn how to use <a href=\"https:\/\/jkunst.com\/highcharter\/\" target=\"_blank\" rel=\"noopener\">highcharter<\/a> and the <a href=\"https:\/\/www.tidyverse.org\/\" target=\"_blank\" rel=\"noopener\">tidyverse<\/a> ecosystem to create an essential replica of the map created by <a href=\"https:\/\/www.theverge.com\/22418074\/broadband-gap-america-map-county-microsoft-data\" target=\"_blank\" rel=\"noopener\">The Verge<\/a>. Are you ready? Let&#8217;s get started! ?<\/p>\n<h2>Libraries<\/h2>\n<p>You will use:<\/p>\n<ul>\n<li>? highcharter for charts.<\/li>\n<li>? janitor to clean the data.<\/li>\n<li>? tidyTuesdayR to download the data.<\/li>\n<li>? tidyverse for full data manipulation.<\/li>\n<li>? widgetframe to transform the chart into an iframe.<\/li>\n<\/ul>\n<pre>\r\nlibrary(highcharter)\r\nlibrary(janitor)\r\nlibrary(tidytuesdayR)\r\nlibrary(tidyverse)\r\nlibrary(widgetframe)\r\n<\/pre>\n<h2>Get the data<\/h2>\n<p>The data used in this article is about the <a href=\"https:\/\/github.com\/microsoft\/USBroadbandUsagePercentages\" target=\"_blank\" rel=\"noopener\">United States Broadbank Usage Percentage Dataset<\/a> <\/p>\n<pre>\r\ntuesday_data <- tidytuesdayR::tt_load(2021, week = 20)\r\n<\/pre>\n<h2>Extract data to use<\/h2>\n<p>A full description of the data can be found in this <a href=\"https:\/\/github.com\/rfordatascience\/tidytuesday\/blob\/master\/data\/2021\/2021-05-11\/readme.md\" target=\"_blank\" rel=\"noopener\">map of America's broadband problem Github link<\/a><\/p>\n<pre>\r\nbroadband <- tuesday_data$broadband %>%\r\n  glimpse()\r\n<\/pre>\n<h2>Download map data<\/h2>\n<p>In the <code>broadband<\/code> table, you will find five columns, of which, <code>COUNTY ID<\/code> represents the identifier of the county in which the broadband usage metrics are being performed.<\/p>\n<p>Therefore, <code>COUNTY ID<\/code> can be used to locate the broadband usage values of each county on a map. Here are several alternatives that you could make use of.<br \/>\nHowever, in this blog, you will use a map of the USA provided by the <code>Highchart<\/code> team.<\/p>\n<p>In particular, <code>highcharter<\/code> provides two utility functions for accessing and browsing different common maps:<\/p>\n<ul>\n<li><code>download_map_data()<\/code>: Download the geojson data from the highchartsJS collection.<\/li>\n<li><code>get_data_from_map()<\/code>: Get the properties for each region in the map, as the keys from the map data.<\/li>\n<\/ul>\n<pre>\r\nmap_layout_data <- download_map_data(\"countries\/us\/us-all-all.js\")<\/pre>\n<p>If you look askance at the columns of the United States map, you will notice that there is a column named <code>fips<\/code>; these are unique 5-digit codes to identify counties in the United States. So, if you consider this, the <code>COUNTY ID<\/code> and <code>fips<\/code> columns are equivalent. Yes, you may have to make a few adjustments later, but stick with that idea for now. ??<\/p>\n<pre>\r\nget_data_from_map(map_layout_data) %>%\r\n  clean_names() %>% \r\n  glimpse()\r\n<\/pre>\n<h2>General preprocessing<\/h2>\n<p>To replicate the map of<br \/>\n<a href=\"https:\/\/www.theverge.com\/22418074\/broadband-gap-america-map-county-microsoft-data\" target=\"_blank\" rel=\"noopener\">The Verge by Microsoft<\/a> (<em>i.e.<\/em>, hereinafter referred as <code>target map<\/code>) you will need to focus only on the two following variables:<\/p>\n<pre>\r\n|variable                       |class     |description |\r\n|:------------------------------|:---------|:-----------|\r\n|county_id                      |double    | County ID |\r\n|broadband_usage                |character | Percent of people per county that use the internet at broadband speeds based on the methodology explained above. Data is from November 2019. |<\/pre>\n<p>But wait... maybe you should be asking yourself why you do not need other indicator variables like <code>ST<\/code> or <code>COUNTY NAME<\/code>?<\/p>\n<p>Well, that's because in a few moments, you will use one of the tables provided by <code>Highcharts<\/code> (described in the section above) to carry out the name mapping of each county. However, in case you don't want to use these provided maps, you could keep the other columns and use packages like <code>zipcodeR<\/code> or <code>tigris<\/code> to help you with the correct mappings. ?<\/p>\n<p>Now, getting back to general data processing, this is a relatively straightforward task. First, and as a good practice, you will use <code>clean_names()<\/code> provided by the <code>janitor<\/code> package to convert the names of the data columns to a standard one. In this way, typing the columns will be simple, easy to remember, and visibly appropriate. ?<\/p>\n<p>Then, you will convert the <code>broadban_usage<\/code> column from a <code>character<\/code> type to a <code>numeric<\/code> type. While you might initially consider using the R base <code>as.numeric()<\/code> or <code>type.convert()<\/code>, <code>type_convert()<\/code> from the <code>reader<\/code> package provides a useful interface if you need to do manual work. Select, clean, and let <code>type_converter()<\/code> take care of the parsing of your variables. ??<\/p>\n<pre>\r\nbroadband_processed <- broadband %>%\r\n  clean_names() %>%\r\n  select(county_id, broadband_usage) %>%\r\n  type_convert(\r\n    col_types = cols(\r\n      broadband_usage = col_double()\r\n    ),\r\n    na = \"-\"\r\n  ) %>%\r\n  glimpse()<\/pre>\n<h2>Prepare data for plot<\/h2>\n<p>Our data is clean, however, to build the <code>target map<\/code> with <code>highcharter<\/code>, you will need to transform it a bit. To begin with, the data does not have information of broadband usage on certain places (<em>i.e.<\/em>, data with <code>NA<\/code>) and, the <code>county_id<\/code> are not  five-character codes, but four-character. Therefore, you must add a zero to those under four characters. ?\u2705<\/p>\n<p>Besides, the <code>target map<\/code> shows two categories to highlight the problem of broadband use. Specifically, those counties that use a broadband speed less than or greater than and equal to 15%. You must apply this condition to categorize the data in the <code>broadband<\/code> table.<\/p>\n<p>Finally, it is time to transform the data into a format that <code>highcharter<\/code> can understand. To do this, you will create a list of series, one serie for each category of the map you want to display. Hence, you will use <code>group_nest()<\/code> to create a subset of data per group. Then, you can add metadata for each series, for example, a color variable. Now, you can transform each subset of data to a list format that <code>highcharter<\/code> can understand with <code>list_parse()<\/code>.<\/p>\n<p>Importantly, each subset has columns named exactly as the base <code>highcharter<\/code> chart needs with some metadata. For example, to recreate the <code>target map<\/code>, each category has the columns: name,  value, and fips. Of which, only <code>fips<\/code> is a metadata variable. ???<\/p>\n<pre>\r\nbroadband_series_data <- broadband_processed %>%\r\n  filter(!is.na(broadband_usage)) %>%\r\n  transmute(\r\n    # Transform to a fips format ------------------------------------------\r\n    fips = str_pad(\r\n      string = county_id,\r\n      width = 5,\r\n      side = \"left\",\r\n      pad = \"0\"\r\n    ),\r\n    # Categorize data -----------------------------------------------------\r\n    value = broadband_usage * 100,\r\n    name = if_else(\r\n      condition = value < 15,\r\n      true = \"< 15%\",\r\n      false = \">= 15%\"\r\n    )\r\n  ) %>%\r\n  # Transform data so that highcharter accepts it. -------------------------\r\n  group_nest(name) %>%\r\n  mutate(\r\n    color = c(\"#0B0073\", \"#B6B8B8\"),\r\n    data = map(data, list_parse)\r\n  ) %>%\r\n  glimpse()<\/pre>\n<p>I need to tell you that there is another way to create choropleths of categorical areas using <a href=\"https:\/\/jkunst.com\/highcharter\/articles\/maps.html#categorized-areas-1\" target=\"_blank\" rel=\"noopener\">dataClasses()<\/a> ?<br \/>\nHowever, honestly, the process of creating the <code>dataClasses<\/code> does not seem as intuitive to me as the version used in this blog (<em>i.e.<\/em>, using <code>group_nest()<\/code>). ?<br \/>\nWho knows. Observe, discuss and leave in the comments how you create them! ??<\/p>\n<h2>United States Broadband Usage Percentages figure<\/h2>\n<p>Well, you've done a ton of stunts to get here, but now is the time to create the <code>target map<\/code>. Are you ready? Let's do it! ???<\/p>\n<p>The first step is to map the data to a graph. For this, you will use <code>highchart()<\/code> to define that the desired graph is of the <code>map<\/code> type.<\/p>\n<p>Next, you will define how you want to display each of your data groups.For instance, groups below or above 15% broadband usage.<br \/>\nUsing <code>hc_plotOptions()<\/code>, you can configure the behavior of each series when plotting. In turn, you can also overwrite the default values by adding more columns of metadata (_e.g._, color) in the data created with <code>list_parse()<\/code>.<br \/>\nSo when you run <code>hc_add_series_list()<\/code>, they will all share the parameters used in <code>hc_plotOptions()<\/code>, but you can always overwrite some as you like ?<\/p>\n<p>Although you built a similar graph to the `target map` with the previous step, it is time for you to add the corresponding text annotations. Normally, HTML within the <code>highcharter<\/code> charts is not necessary, much less mandatory. However, if required, you can use the <code>useHTML = TRUE<\/code> parameter within each display text call (_e.g._, <code>hc_title()<\/code>, <code>hc_subtitle()<\/code>, etc.). In this way, all the strings that you define will be treated as HTML, and you will have greater control over how and where to display specific pieces of text. ?<\/p>\n<p>The result so far should look almost identical; only one thing is missing; the navigation buttons. By default, the navigation buttons are disabled, so you must activate them with <code>hc_mapNavigation()<\/code>. To position it in a specific place, use the <code>buttonOptions<\/code> parameter. With it, you can change the alignment with the parameters <code>align<\/code>, <code>verticalAlign<\/code>. To mention, you can also find these parameters in the positioning of the legend or texts. ?<\/p>\n<p>It would be best to use <code>frameWidget()<\/code> to display <code>highcharter<\/code> plots within static pages. Inside a Rmarkdown or a Shiny app, it might not be necessary. ?<\/p>\n<pre>\r\nhighchart(\r\n  type = \"map\"\r\n) %>%\r\n  # How do you want to display the data? ----------------------------------\r\n  hc_plotOptions(\r\n    map = list(\r\n      allAreas = FALSE,\r\n      joinBy = \"fips\",\r\n      value = \"value\",\r\n      mapData = map_layout_data\r\n    ),\r\n    series = list(\r\n      states = list(\r\n        inactive = list(\r\n          opacity = 0.7\r\n        )\r\n      )\r\n    )\r\n  ) %>% \r\n  hc_add_series_list(broadband_series_data) %>%\r\n  # Display text as in original source. -----------------------------------\r\n  hc_title(\r\n    text = \"\r\n      &lt;p style='text-align:center;'&gt;\r\n        &lt;b&gt;THIS IS A MAP OF AMERICAN'S BROADBAND PROBLEM&lt;\/b&gt;\r\n        &lt;br&gt;\r\n        A county-by-county look at the broadband gap\r\n      &lt;\/p&gt;\r\n    \",\r\n    align = \"center\",\r\n    useHTML = TRUE\r\n  ) %>%\r\n  hc_subtitle(\r\n    text = \"\r\n      By <a href=''>Russell Brandom<\/a>\r\n      and <a href=''>William Joel<\/a> | May 10, 2021, 9:00am EDT\r\n    \",\r\n    align = \"center\",\r\n    useHTML = TRUE\r\n  ) %>%\r\n  hc_caption(\r\n    text = \"\r\n      Map: The Verge. The database does not include broadband rates for\r\n      Oglala Lakota County, South Dakota, or Kusilvak Census Area, Alaska,\r\n      because of a coding irregularity. Source: \r\n      &lt;a href='https:\/\/github.com\/microsoft\/USBroadbandUsagePercentages'&gt;\r\n        Microsoft\r\n      &lt;\/a&gt; \r\n       - \r\n      &lt;a href='https:\/\/www.theverge.com\/22418074\/broadband-gap-america-map-county-microsoft-data'&gt;\r\n      Get the data\r\n      &lt;\/a&gt;.\r\n    \",\r\n    useHTML = TRUE\r\n  ) %>%\r\n  hc_legend(\r\n    title = list(\r\n      text = \"\r\n        Percentage of people using the internet at 25Mbps or above per county.\r\n        \"\r\n      ),\r\n    align = \"left\",\r\n    symbolHeight = 12,\r\n    symbolWidth = 12,\r\n    symbolRadius = 0,\r\n    squareSymbol = FALSE\r\n  ) %>%\r\n  hc_tooltip(\r\n      pointFormat = \"\r\n        &lt;b&gt;{point.name}&lt;\/b&gt;&lt;br&gt;\r\n        &lt;br&gt;\r\n        &lt;b&gt;{point.value}%&lt;\/b&gt;&lt;br&gt;\r\n        Percent using broadband speed\r\n        \",\r\n      useHTML = TRUE\r\n  ) %>%\r\n  hc_credits(\r\n    text = \"\r\n      &lt;b&gt;Replica made by: &lt;\/b&gt; \r\n      &lt;a href='https:\/\/twitter.com\/jvelezmagic'&gt;@jvelezmagic&lt;\/a&gt;\r\n    \",\r\n    enabled = TRUE,\r\n    useHTML = TRUE\r\n  ) %>%\r\n  # Customize zoom options ------------------------------------------------\r\n  hc_mapNavigation(\r\n    enabled = TRUE,\r\n    enableMouseWheelZoom = FALSE,\r\n    buttonOptions = list(\r\n      align = \"right\",\r\n      verticalAlign = \"bottom\"\r\n    )\r\n  ) %>%\r\n  # Include your favorite theme! -----------------------------------------\r\n  hc_add_theme(\r\n    hc_thm = hc_theme_elementary()\r\n  ) %>%\r\n  # Display as iframe -----------------------------------------------------\r\n  frameWidget() %>% \r\n  identity()\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wp-assets.highcharts.com\/www-highcharts-com\/blog\/wp-content\/uploads\/2021\/06\/10142550\/Screenshot-2021-06-10-at-14.24.57.jpg\" alt=\"A map of American&#039;s Broadband Problem\" width=\"1160\" height=\"587\" class=\"alignnone size-full wp-image-21692\" \/><\/p>\n<p>Congratulations, you have learned to create a handy map to share and show a problem of interest. I hope to see you soon with another blog. ?\u2728\u2728\u2728 <\/p>\n<p>Feel free to share your comments in the comment section below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A step-by-step tutorial to learn how to create an interactive chart using Tidytuesday and Highcharter.<\/p>\n","protected":false},"author":265,"featured_media":20916,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"meta_title":"","meta_description":"","hc_selected_options":[],"footnotes":""},"categories":[1105],"tags":[876,793],"coauthors":[895],"class_list":["post-20914","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-integration","tag-highcharts-maps","tag-r"],"_links":{"self":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/20914","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/users\/265"}],"replies":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/comments?post=20914"}],"version-history":[{"count":2,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/20914\/revisions"}],"predecessor-version":[{"id":29350,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/posts\/20914\/revisions\/29350"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media\/20916"}],"wp:attachment":[{"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/media?parent=20914"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/categories?post=20914"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/tags?post=20914"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.highcharts.com\/blog\/wp-json\/wp\/v2\/coauthors?post=20914"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}