Origin and development of a Snowflake Map
Reproducible code demonstrating the evolution of a recent data viz of CONUS snow cover
What's on this page
The result
It’s been a snowy winter, so let’s make a snow cover map! This blog outlines the process of how I made a snowflake hex map of the contiguous U.S. The final product shows whiter snowflakes where snow cover was higher, which was generally in the northern states and along the main mountain ranges. I used a few interesting tricks and packages (e.g., ggimage , magick ) to make this map and overlay the snowflake shape. Follow the steps below to see how I made it.

Final map released on Twitter.
The concept
This is a creation from the latest data visualization “Idea Blitz” with the USGS VizLab , where we experiment with new ideas, techniques or data.
My goal for the Idea Blitz was to create a map that showed average snow cover for the United States in a new and interesting way. My thought was that it would be cool to show a map of snow cover using snowflake shapes. Hexbin maps are fairly popular right now (example ), and I imagined a spin on the classic choropleth hexmap that showed mean snow coverage with a hexagonal snowflake-shaped mask over each state.

Concept sketch of the map.
The data
On ScienceBase I found a publicly-available dataset that had exactly what I was looking for: “Contiguous U.S. annual snow persistence and trends from 2001-2020.” (Thanks John Hammond !). These rasters provide Snow Cover Index (SCI) from 2001 through 2020 for the contiguous United States using MODIS/Terra Snow Cover 8-day L3 Global 500m Grid data. The SCI values are the fraction of time that snow is present on the ground from January 1 through July 3 for each year in the time series.
One note: At this point, I am limited by this dataset and the fact that it doesn’t include Alaska or Hawaii in its extent. My goal is to use the MODIS data directly in a future rendition so that I can include the complete U.S.
The data and code are open and reproducible so that you can try it out for yourself! Tweet @USGS_DataSci with your spin-off ideas, we’d love to see what you come up with!
Step 1. Download the snow cover index data
To begin, download the geotif raster files for SCI from 2001 through 2020 using the sbtools
package. After reading in the data files as a raster stack, calculate the mean across the 20 years for each raster cell, and plot it to see what the data look like.

Map of 20-year-mean Snow Cover Index as downloaded from Science Base.
Step 2: Summarize the SCI values by state
My original concept was to make a state-level hexbin map. I started by spatially averaging the snow cover data to each state’s boundary. To do this, import CONUS state boundaries and re-project them to match the raster’s projection. Then, extract 20-year mean SCI values from the raster to the state polygon boundaries and summarize by state. Then let’s plot the results as a choropleth to see what it looks like. I’m using a dark plot background to make the snowier whites show up with high contrast against the deep blue background.

Map of 20-year-mean Snow Cover Index spatially summarized by state.
Step 3: Make a state-level hexmap choropleth
To remind you, my goal was to use a snowflake shape over the choropleth, so I wanted the states to be hexagonal in shape to mirror the shape of a snowflake. To convert the states into hexagons, download a pre-made dataset of the hexagons in a geojson
file format. Import this as an sf object
, ready for plotting, and join with the mean SCI data to create the choropleth.

Map of 20-year-mean Snow Cover Index spatially summarized by state, with each state shaped like a hexagon.
Step 4: Make a snowflake state-level hexmap choropleth
Finally, the first draft of my hexagon choropleth is ready for refinement, including the addition of the snowflake mask that I created in Illustrator. This png has a transparent background and will allow the color of the state to show through.

Vectorized snowflake mask, ready for all your mapping uses!
To make this rendition, use the packages ggimage
and cowplot
to overlay the png and create a 16x9 composition, respectively. There are two tricks to using the ggimage
overlay approach here. First, note that it’s necessary to use the st_coordinates()
function to extract the coordinates in a form that ggimage
can read. Secondly, the aspect ratio and size arguments of the geom_image
function (asp
and size
, respectively) need to be toggled until they fit the map’s hexagon shape and size. Finally, I used a free typeface from Google fonts that felt like it had that winter holiday style I was going for.

Map of 20-year-mean Snow Cover Index spatially summarized by state, with each state shaped like a hexagon. This was the first draft shared back to the Vizlab team.
It was really cool to see my first idea come to life in this map!
Step 5: Refine the snowflake map with a finer resolution hexmap
The image above was shared out with my working group, and although we all thought it was neat, it also doesn’t really show enough variety of snow pack in the contiguous U.S. – each state has areas of higher and lower snowfall that are not represented at this coarse scale. To address this, we decided on a more customized hexagon grid that had finer resolution than state-level.
Using a built-in feature of the package sf
, st_make_grid()
, create a hexagonal spatial grid over the contiguous United States, using the state boundaries as the extent. Map that over the boundaries to get an idea for how small these new hexagons are in relation to the state boundaries.

Map that shows the size and shape of the hexagonal grid in relation to the state boundaries.
Next, follow the same steps as above to extract the 20-year mean SCI values to each hexagon and recreate the map, this time with a much finer resolution snowflake.

This map version shows a lot more detail in where snow is across the contiguous United States. Just need to add on the snowflake mask!
Next, add in the snowflake mask as a png. Again, it’s necessary to use the st_coordinates(st_centroid())
functions to extract the centroid coordinates in a form that the ggimage
package can read, and the aspect ratio and size of the image will have to be tweaked again to match the new, smaller hexagons.

This snowflake map turned out better than I had hoped. Next step is to clean up the map composition and add in text and legends.
Step 6: Finalize the map and customize the layout
The last thing to do is make a custom legend, add in the USGS logo, and clean everything up for sharing out. A cool trick I’m going to use for the custom legend is to take the snowflake mask and use the package magick
to colorize it so that it matches the colors used in the scico
palette. Functions are used here to systematically produce a custom legend with staggered snowflakes and text labels.
I made the final image for Twitter in a 16x9 format with the ggsave
function.
Twitter layout

Final map released on Twitter.
And with that, you have all the code and the snowflake mask to make these maps or your own version of a snow map!
Special thanks to Cee , Hayley , Elmera , Anthony , Nicole , and Mandie for their help with this viz.
Related Posts
The Hydro Network-Linked Data Index
November 2, 2020
Introduction updated 11-2-2020 after updates described here . updated 9-20-2024 when the NLDI moved from labs.waterdata.usgs.gov to api.water.usgs.gov/nldi/ The Hydro Network-Linked Data Index (NLDI) is a system that can index data to NHDPlus V2 catchments and offers a search service to discover indexed information.
Jazz up your ggplots!
July 21, 2023
At Vizlab , we make fun and accessible data visualizations to communicate USGS research and data. Upon taking a closer look at some of our visualizations, you may think:
Mapping water insecurity in R with tidycensus
December 9, 2024
Water insecurity can be influenced by number of social vulnerability indicators—from demographic characteristics to living conditions and socioeconomic status —that vary spatially across the U.
Reproducible Data Science in R: Flexible functions using tidy evaluation
December 17, 2024
Overview This blog post is part of a series that works up from functional programming foundations through the use of the targets R package to create efficient, reproducible data workflows.
Reproducible Data Science in R: Iterate, don't duplicate
July 18, 2024
Overview This blog post is part of a series that works up from functional programming foundations through the use of the targets R package to create efficient, reproducible data workflows.