Leaflet is an open-source JavaScript library for making dynamic maps for the web. RStudio wrote R bindings for Leaflet, available through its leaflet package, built with htmlwidgets. Leaflet maps integrate well with the RMarkdown and Shiny ecosystems.

The interface is piped, using a leaflet() function to initialize a map and subsequent functions adding (or removing) map layers. Many kinds of layers are available, from markers with popups to polygons for creating choropleth maps. Variables in the data.frame passed to leaflet() are accessed via function-style ~ quotation.

To map the state.name and state.center datasets:

library(leaflet)
data.frame(state.name, state.center) %>% 
  leaflet() %>% 
  addProviderTiles('Stamen.Watercolor') %>% 
  addMarkers(lng = ~x, lat = ~y, 
             popup = ~state.name, 
             clusterOptions = markerClusterOptions())
LS0tCnRpdGxlOiAiTWFraW5nIER5bmFtaWMgSFRNTCBNYXBzIHdpdGggTGVhZmxldCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IAogICAgdGhlbWU6IGZsYXRseQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgpbTGVhZmxldF0oaHR0cDovL2xlYWZsZXRqcy5jb20vKSBpcyBhbiBvcGVuLXNvdXJjZSBKYXZhU2NyaXB0IGxpYnJhcnkgZm9yIG1ha2luZyBkeW5hbWljIG1hcHMgZm9yIHRoZSB3ZWIuIFJTdHVkaW8gd3JvdGUgUiBiaW5kaW5ncyBmb3IgTGVhZmxldCwgYXZhaWxhYmxlIHRocm91Z2ggaXRzIFtgbGVhZmxldGAgcGFja2FnZV0oaHR0cDovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvKSwgYnVpbHQgd2l0aCBbYGh0bWx3aWRnZXRzYF0oaHR0cDovL3d3dy5odG1sd2lkZ2V0cy5vcmcvc2hvd2Nhc2VfbGVhZmxldC5odG1sKS4gTGVhZmxldCBtYXBzIGludGVncmF0ZSB3ZWxsIHdpdGggdGhlIFtSTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vKSBhbmQgW1NoaW55XShodHRwOi8vc2hpbnkucnN0dWRpby5jb20vKSBlY29zeXN0ZW1zLgoKVGhlIGludGVyZmFjZSBpcyBbcGlwZWRdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vZG9jdW1lbnRhdGlvbi9yLzY1Mi9waXBlLW9wZXJhdG9ycy1hbmQtb3RoZXJzKSwgdXNpbmcgYSBgbGVhZmxldCgpYCBmdW5jdGlvbiB0byBpbml0aWFsaXplIGEgbWFwIGFuZCBzdWJzZXF1ZW50IGZ1bmN0aW9ucyBhZGRpbmcgKG9yIHJlbW92aW5nKSBtYXAgbGF5ZXJzLiBNYW55IGtpbmRzIG9mIGxheWVycyBhcmUgYXZhaWxhYmxlLCBmcm9tIG1hcmtlcnMgd2l0aCBwb3B1cHMgdG8gcG9seWdvbnMgZm9yIGNyZWF0aW5nIGNob3JvcGxldGggbWFwcy4gVmFyaWFibGVzIGluIHRoZSBkYXRhLmZyYW1lIHBhc3NlZCB0byBgbGVhZmxldCgpYCBhcmUgYWNjZXNzZWQgdmlhIGZ1bmN0aW9uLXN0eWxlIGB+YCBxdW90YXRpb24uCgpUbyBtYXAgdGhlIFtgc3RhdGUubmFtZWAgYW5kIGBzdGF0ZS5jZW50ZXJgIGRhdGFzZXRzXShodHRwOi8vc3RhdC5ldGh6LmNoL1ItbWFudWFsL1ItcGF0Y2hlZC9saWJyYXJ5L2RhdGFzZXRzL2h0bWwvc3RhdGUuaHRtbCk6CgpgYGB7ciwgZmlnLndpZHRoPTEwfQpsaWJyYXJ5KGxlYWZsZXQpCmRhdGEuZnJhbWUoc3RhdGUubmFtZSwgc3RhdGUuY2VudGVyKSAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBhZGRQcm92aWRlclRpbGVzKCdTdGFtZW4uV2F0ZXJjb2xvcicpICU+JSAKICBhZGRNYXJrZXJzKGxuZyA9IH54LCBsYXQgPSB+eSwgCiAgICAgICAgICAgICBwb3B1cCA9IH5zdGF0ZS5uYW1lLCAKICAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSkKYGBg