Skip to content

🌊 πŸ“‰ A Python, Django, Plotly, and Pandas web application that visualizes river data in real time, pulled using an API from the United States Geological Survey (USGS).

License

Notifications You must be signed in to change notification settings

scottgriv/River-Charts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

App Logo

Python Badge Django Badge Plotly Badge Pandas Badge
GitHub Badge Email Badge BuyMeACoffee Badge
Gold PRG Badge


🌊 River Charts πŸ“ˆπŸ“‰

River Charts is a Python, Django, Plotly, and Pandas web application that visualizes river data for a specific river/site/location.

  • The line graph is driven by data pulled using an API from the United States Geological Survey (USGS).
    • The data is captured by the USGS using a gage height sensor every 15 minutes.
  • The data is updated with the most recent river height data every time the application is loaded.
    • Please be patient, the loading time of the application is around 30+ seconds (depending on your internet connection), due to the large API JSON response and the amount of data being processed from the USGS.
    • The application can be configured to pull live data in via the API or use a static .json file to display a snapshot of data.
  • The loading screen screen contains fun wave and tube graphics as well as 20 "Fun Facts" regarding Tubing and Rivers on a 7 second interval to keep the user occupied while the data is loading in the background.
  • I recommend using the application on a desktop since the chart is interactive has a wider view, but it can be used on a mobile device as well.
  • Visit the application here.
Demo_1 Demo_2

Table of Contents

Features

  • Responsive: The application is responsive and can be used on a mobile device.
  • Interactive: The application uses Plotly to create an interactive line graph.
  • Data Visualization: The application visualizes river data for a specific river/site/location.
  • Data Source: The application sources data using an API that returns JSON output.
  • Data Processing: The application processes the JSON output and converts it to a Pandas DataFrame.
  • Data Manipulation: The application manipulates the DataFrame to create a Plotly line graph.
  • Data Update: The application updates the data with the most recent river height data every time the application is loaded.
  • Data Capture: The data is captured by the USGS using a gage height sensor every 15 minutes.

Background Story

Every year, my friends and I float 2 miles down the Susquehanna River in NEPA on river tubes (a 2 hour float). I wanted to create a web application that would allow us to visualize past river data in order to see the river height on the days we floated down the river. Some float dates, we still got together, but we didn't float due to the dangerous river levels.

Below is the key to use when viewing the plots on the graph for Float dates:

Color Hex Floated Status Floated Key
Green #008000 #008000 Yes (Met up and did Float) Y
Red #FF0000 #FF0000 No (Met up, but did not Float) N
Orange #FFA500 #FFA500 Skipped (Skipped the event altogether) S

Note

The closest river gage to our float location is the Susquehanna River at Meshoppen, PA, which is the default site code in the application. You can change the site code in the application config.py file to visualize data for a different river/site code.


West Branch, Susquehanna River.


The application uses gage height data to plot the river height in feet on a given date.

Definitions

Here are some definitions to help you understand the terminology used in this document:

  • USGS: The United States Geological Survey. The USGS is a science organization that provides impartial information on the health of our ecosystems and environment, the natural hazards that threaten us, the natural resources we rely on, the impacts of climate and land-use change, and the core science systems that help us provide timely, relevant, and useable information.
  • Gage Height: The height of the water surface above the gage datum (zero point). Gage height is often used interchangeably with the more general term, stage, although gage height is more appropriate when used with a gage reading. Stage is more appropriate when used with a recorded or calculated gage height.

Getting Started

Dependencies

This project makes use of several libraries and frameworks:

  • Python: For the application logic.
  • Django: For web application functionality.
  • Plotly: For creating interactive visualizations.
  • Pandas: For data manipulation and analysis.
  • Requests: For making API calls.
  • Python-Decouple: For storing sensitive information in a .env file.
  • See requirements.txt for a full list of dependencies.

Configuration

  • Edit config.py to add your own USGS API (and other) information.
  • Toggle USE_DUMMY_DATA to True in config.py to use dummy data instead of the API.
    • This is useful for testing the application without making API calls.
  • Toggle USE_SNAPSHOT_DATA to True in config.py to use snapshot/static data instead of the API.
    • This is useful for avoiding API calls and using a static data set in the data/snapshot.json file.
    • You will need to populate the file with JSON by calling the "Historical River Levels" API call in Postman, included in this project (docs/api/River Charts.postman_collection.json); see Calling the API below for more information.
    • Your app will esentially be a snapshot, and not live updates using this method, but it can be helpful if you want to avoid server costs making API calls.
  • The float data plots are driven from a .csv file located in static/data/river_charts.csv.
    • This file can be edited to add/remove float dates.
    • The file is read in views.py and passed to the template as a context variable.

Installation

To install and run the project locally, follow the steps below:

  1. Clone the repository:

    git clone https://github.com/scottgriv/River-Charts
  2. Navigate to the project directory:

    cd [YOUR PROJECT DIRECTORY]
  3. Create a virtual environment:

    python -m venv venv
  4. Activate the virtual environment:

    source venv/bin/activate
  5. Install the required packages using requirements.txt:

    pip install -r requirements.txt

    Note: If you wany to generate a new requirements.txt file, run the following command:

    pip freeze > requirements.txt
  6. Run the Django server:

    python manage.py runserver

Now, you can visit http://127.0.0.1:8000/ in your browser to access the application.

Deployment

  • The application is hosted here on PythonAnywhere.
  • The application is deployed using a WSGI configuration file.
  • First, make sure you adjust your settings.py file ALLOWED_HOSTS to include your deployment host.
  • Second, make sure you adjust your settings.py file DEBUG to False for production.
  • Finnaly, be sure to create a .env file where you host your application to store your sensitive information (excluded from this repository).

What's Inside?

Below is a list of the main files and folders in this repository and their specific purposes:

River-Charts # Root folder
β”œβ”€ .github # GitHub related files such as CHANGELOG, CREDITS, etc.
β”œβ”€ docs # Included resources.
β”‚Β Β  β”œβ”€ api # API resources.
β”‚Β Β  β”‚Β Β  └─ River Charts.postman_collection.json # A Postman Collection used to manually call the API, and to gather data if you want to use this as a static site.
β”‚Β Β  β”œβ”€ assets # Misc. resources.
β”‚Β Β  β”‚Β Β  └─ stage versus flow slide.pdf # A PDF file that explains stage vs. flow slide.
β”‚Β Β  └─ images # Image resources.
β”œβ”€ River_Charts # The Django project directory.
β”‚Β Β  β”œβ”€ __init__.py # An empty file that tells Python that this directory should be considered a Python package.
β”‚Β Β  β”œβ”€ asgi.py # An entry-point for ASGI-compatible web servers to serve your project.
β”‚Β Β  β”œβ”€ settings.py # Settings/configuration for this Django project.
β”‚Β Β  β”œβ”€ urls.py # The URL declarations for this Django project.
β”‚Β Β  └─ wsgi.py # An entry-point for WSGI-compatible web servers to serve your project.
β”œβ”€ rivercharts # A directory for the rivercharts app.
β”‚Β Β  β”œβ”€ templates # A directory for HTML templates.
β”‚Β Β  β”‚Β Β   β”œβ”€ rivercharts # A directory for HTML templates specific to the river_charts app.
β”‚Β Β  β”‚Β    β”œβ”€ error.html # An HTML template that displays an error message.
β”‚Β Β  β”‚Β    └─ index.html # An HTML template that displays the application.
β”‚Β Β  β”œβ”€ __init__.py # An empty file that tells Python that this directory should be considered a Python package.
β”‚Β Β  β”œβ”€ admin.py # A file that registers models to be displayed in the Django admin site.
β”‚Β Β  β”œβ”€ apps.py # A file that contains the application configuration.
β”‚Β Β  β”œβ”€ config.py # A file that contains sensitive information (excluded from this repository).
β”‚Β Β  β”œβ”€ models.py # A file that contains the database models.
β”‚Β Β  β”œβ”€ tests.py # A file that contains the tests for the application.
β”‚Β Β  β”œβ”€ urls.py # A file that contains the URL declarations for the application.
β”‚Β Β  └─ views.py # A file that contains the application logic.
β”œβ”€ static # A directory for static files that are used in this Django project.
β”‚Β Β  β”œβ”€ assets # A directory images used throughout the application.
β”‚Β Β  β”œβ”€ css # A directory for CSS files.
β”‚Β Β  β”‚Β Β  └─ styles.css # A CSS file that contains the styles for the application.
β”‚Β Β  β”œβ”€ data # A directory for data files.
β”‚Β Β  β”‚Β Β  β”œβ”€ fun_facts.json # A JSON file used to display Fun Facts while the application is loading, add or remove more facts here.
β”‚Β Β  β”‚Β Β  β”œβ”€ snapshot.json # A JSON file used for static data when USE_SNAPSHOT_DATA is set to True in config.py.
β”‚Β Β  β”‚Β Β  └─ river_charts.csv # A CSV file that contains the float dates for the application.
β”‚Β Β  β”œβ”€ fonts # A directory fonts used throughout the application.
β”‚Β Β  └─ js # A directory for JavaScript files.
β”‚Β Β  Β Β   └─ script.js # The JavaScript file used to render the loading screen. 
β”œβ”€ requirements.txt # A list of Python packages required to run this project.
β”œβ”€ db.sqllite3 # A database file Django uses for this project (Do not delete).
β”œβ”€ manage.py # A command-line utility that lets you interact with this Django project in various ways.
β”œβ”€ .github # GitHub folder
β”œβ”€ .gitignore # Git ignore file
β”œβ”€ .gitattributes # Git attributes file
β”œβ”€ PRG.md # PRG Connection File
β”œβ”€ LICENSE # A file that contains the license for this project.
β”œβ”€ VERSION # A file used to keep the repository release and the PythonAnywhere deployment in sync.
└─ README.md # This file.

API Documentation

Below is the documentation for the API used in this application.

Calling the API

To call the API and retrieve the data:

  1. Make a GET request to: http://nwis.waterservices.usgs.gov/nwis/... (based on your requirements).

    • ex. https://waterservices.usgs.gov/nwis/iv?format=json&sites=01533400&startDT=2015-07-01&endDT=2023-08-16&parameterCd=00065&siteStatus=active&siteType=ST
  2. Pass the necessary parameters in the request.

    • ex.
    params = {
        "format": "json", # Set your interchange format.
        "sites": "01533400", # Site Code: Susquehanna River at Meshoppen, PA.
        "startDT": "2015-07-01", # Set the date you want to start collecting data from.
        "endDT": "2023-09-14", # This is based on the current date in the application.
        "parameterCd": "00065", # Parameter Code: Gage height, ft.
        "siteStatus": "active", # Selects sites based on whether or not they are currently active. Each USGS Water Science Center determines whether a site is active or inactive. The default is all (show both active and inactive sites).
        "siteType": "ST", # ST = A body of running water moving under gravity flow in a defined channel. The channel may be entirely natural, or altered by engineering practices through straightening, dredging, and (or) lining. An entirely artificial channel should be qualified with the "canal" or "ditch" secondary site type.
    }
  3. Process the JSON response as demonstrated in the example above.

Notes:

  • The application uses the API to source data for the graph. If the API is down, the graph will not render.
  • Errors are handled in the application by redirecting the user to an error page with the appropriate error message.
    • HTTP errors are handled in the application by redirecting the user to an error page with the appropriate error message.
    • The application will also display an error message if the API returns an empty response or a timeout error (default is set to 90 seconds in config.py).
    • The API is rate limited to 30 calls per minute. If you exceed this limit, you will receive a 429 error.

Example of an Error Page.

API Output Example

The application sources data using an API that returns JSON output. Here's an example of what the API response looks like:

{
    "name": "ns1:timeSeriesResponseType",
    ...
    "timeSeries": [
        {
            "sourceInfo": {
                "siteName": "Susquehanna River at Meshoppen, PA",
                ...
            },
            "variable": {
                "variableName": "Gage height, ft",
                ...
            },
            "values": [
                {
                    "value": [
                        {
                            "value": "15.13",
                            "dateTime": "2015-07-01T00:00:00.000-04:00"
                        },
                        ...
                    ]
                }
            ]
        }
    ]
}

(For the sake of brevity, the full output is abbreviated with ...)

Disclaimer

  • The data provided by this application is sourced from the USGS.
  • It's subject to revision, and for more information, please refer to their official disclaimer.
  • Software is provided as-is and no warranty is given about its usability.

Closing

Thank you for taking the time to read through this document and I hope you find it useful! If you have any questions or suggestions, please feel free to reach out to me.

Please reference the SUPPORT file in this repository for more details.

What's Next?

I'm looking forward to seeing how this project evolves over time and how it can help others with their GitHub Portfolio.

Please reference the CHANGELOG file in this repository for more details.

Project

Please reference the GitHub Project tab inside this repository to get a good understanding of where I'm currently at with the overall project.

  • Issues and Enhancements will also be tracked there as well.

Contributing

Feel free to submit a pull request if you find any issues or have any suggestions on how to improve this project. You can also open an issue with the tag "bug" or "enhancement".

  • How to contribute:
  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/River-Charts)
  3. Commit your Changes (git commit -m 'Add new feature')
  4. Push to the Branch (git push origin feature/River-Charts)
  5. Open a Pull Request

Please reference the CONTRIBUTING file in this repository for more details.

Resources

Below are some external resources I found helpful when creating River Charts:

Technical Resources

  • Python - A programming language that lets you work quickly and integrate systems more effectively.
  • Django - A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
  • Plotly - A Python graphing library that makes interactive, publication-quality graphs online.
  • Pandas - A fast, powerful, flexible and easy to use open source data analysis and manipulation tool.
  • Requests - A simple, yet elegant HTTP library.
  • Python-Decouple - A Python library for separating the settings of your Django/Flask/FastAPI project from the source code.
  • Deploying Django - A tutorial on how to deploy Django.
  • Django Settings - A list of all settings available in Django.
  • Running the Django server - A tutorial on how to run the Django server.
  • Creating Virtual Environments - A tutorial on how to create virtual environments.
  • Activating a virtual environment - A tutorial on how to activate a virtual environment.
  • Installing Packages - A tutorial on how to install packages using pip.
  • Requirements Files - A file containing a list of items to be installed using pip install like so: pip install -r requirements.txt.
  • PythonAnywhere - A Python hosting provider with a free tier.

Note

To use external API's (like this application does), PythonAnywhere requires a basic paid tier.

Educational Resources

License

This project is released under the terms of the GNU General Public License, version 3 (GNU GPLv3), which ensures that derivatives of the software remain open source.

  • The GNU GPLv3 is a "copyleft" license, ensuring that derivatives of the software remain open source and under the GPL.
  • For more details and to understand all requirements and conditions, see the LICENSE file in this repository.

Credit

Author: Scott Grivner
Email: scott.grivner@gmail.com
Website: scottgrivner.dev
Reference: Main Branch