Interactive Geospatial Explorer
Build an interactive map web app in R with Shiny. It loads a dataset of geographic points, for example earthquakes, public facilities or observation records, and shows them on a Leaflet map where users can filter by category, date range and numeric values, or draw a rectangle on the map to select an area. A table below the map shows the selected features, and the selection can be exported as CSV or GeoJSON. The app stays fast with tens of thousands of points by filtering efficiently and clustering markers. You'll learn Shiny reactivity in depth (reactive expressions, debouncing, modules), spatial data with sf, interactive maps with leaflet, and structuring a larger Shiny app so it stays maintainable and testable.
- Estimate
- ~14.5h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
tidyverse · Shiny
Project roadmap
- 01
Choose and prepare the data
~2hPick a public point dataset with at least 20,000 records, coordinates, a category, a date and a numeric value, for example the USGS earthquake catalog for one year. Write R/prepare_data.R that reads it with the tidyverse, removes rows with missing or impossible coordinates, converts it to an sf object with st_as_sf (crs 4326), and saves it as data/points.rds. Note the source and license in the README. Done when: the script produces points.rds and prints how many rows were kept.
- 02
Show the points on a map
~2hCreate app.R with a sidebar layout, loading points.rds once at startup. Draw the points on a leaflet map (renderLeaflet) with marker clustering, colored by category, with a legend and a popup showing each point's details. Done when: the app opens with all points shown as clustered markers.
- 03
Add the filters
~2.5hAdd filter controls: a multi-select for category, a date range input and a slider for the numeric value. Build one reactive expression that returns the filtered data. Update the markers with leafletProxy instead of redrawing the whole map, so the view doesn't reset, and debounce the slider so dragging it doesn't trigger dozens of updates. Done when: changing a filter updates the markers quickly without resetting the map view.
- 04
Select an area on the map
~2.5hAdd drawing tools with the leaflet.extras package (rectangle and polygon only). When the user draws a shape, turn it into an sf polygon and keep only the filtered points inside it using st_filter. Add a Clear selection button. Show how many points are selected. Done when: drawing a rectangle limits the selection to the points inside it.
- 05
Show a table of the selection
~1.5hBelow the map, show the selected features in a DT table with sortable columns and search. Clicking a row pans the map to that point and opens its popup. Done when: the table always matches the current filters and drawn area, and clicking a row focuses the point on the map.
- 06
Export the selection
~1.5hAdd two download buttons with downloadHandler: CSV (with longitude and latitude columns) and GeoJSON (written with sf::st_write). The file names include the date and the number of features. Disable the buttons when nothing is selected. Done when: both exports contain exactly the selected features and open correctly in another tool, such as geojson.io.
- 07
Organize with modules and test
~2.5hSplit the app into Shiny modules: filters, map and table. Move the filtering logic into plain functions in R/ and test them with testthat (category, dates, value range, and selection by polygon). Add one testServer test that checks the filtered data reacts to input changes. Done when: the app works after the refactor and all tests pass.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack