Creating a Simple Static Webpage#

So far in Python for Nonprofits, you’ve learned how to import, prepare, analyze, and visualize data. However, the analyses and visualizations that you create will be of limited use unless you can can easily share them with others. Thus, this final part of PFN will introduce various options for publishing analyses online. This notebook will cover static webpages, but subsequent sections will introduce Google Sheets and interactive Dash apps as alternative publication methods.

Static websites#

A simple way to share visualizations and other data online is through a static website. The content in such websites is relatively fixed, unlike with dynamic websites (such as Dash apps). If you have a set of content that doesn’t need to be updated very regularly, if at all, a static site might be your best option.

For instance, we created some colorful net migration and population growth maps within the Mapping section of PFN. To share those maps with others, we could send them directly as HTML files; our users could then open those maps within a web browser. However, a simpler approach (at least for the end user) would be to share them online via a static website. We’ll learn how to do so within this section.

Note: the static website created by this notebook can be found at https://kburchfiel.github.io/simple_static_site/. The repository that contains this website’s contents is available at kburchfiel/simple_static_site .

Creating Static Sites with GitHub Pages#

One option (among others) for hosting static content online for free is GitHub Pages (https://pages.github.com/). The GitHub pages documentation is quite robust, so I’ll merely summarize the steps that I took. (Selecting the ‘Project site’ and ‘Start from scratch’ options will let you view the steps that most closely resembled my workflow–though I did certain steps a bit differently.) The static website I’ll create within this notebook should serve as a helpful reference if you get stuck along the way.

(I do recommend reviewing the GitHub Pages terms of service at https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages#prohibited-uses in order to make sure that this service is a good option for your static hosting needs, as certain uses are prohibited.)

Preparing local copies of the site’s materials#

First, I created a new repository (kburchfiel/simple_static_site) in which I could store my maps. Next, I created a corresponding ‘simple_static_site’ folder within my computer’s file system.

I then ran the following code in order to copy some (but not all) of the maps created within PFN’s mapping section into this folder. (If you wish to run this code as well, you’ll need to create the corresponding ‘../../simple_static_site/maps/’ folder within your computer also. In order for the relative paths to work correctly, the ‘simple_static_site’ folder should be located within the same folder that contains your Python for Nonprofits folder.)

For more on the shutil.copyfile() function used below, see https://docs.python.org/3/library/shutil.html .

import shutil
# Defining the original location of these maps--and the location
# to which they'll be copied:
source_map_folder = '../Mapping/maps/' # This folder exists within 
# the main Python for Nonprofits folder.
dest_map_folder = '../../simple_static_site/maps/' # This folder
# is in a separate location from Python for Nonprofits
# Specifying which maps within the source folder to copy:
maps_to_copy = ['net_migration_rate_state_2020-2024.html',
                'net_migration_rate_county_2020-2024.html',
                'state_25-29_pop_pct_growth_2011-2021.html',
                'state_pop_pct_growth_2011-2021.html',
                'county_25-29_pop_pct_growth_2011-2021_tiled.html',
                'county_pop_pct_growth_2011-2021_tiled.html']
for map_for_site in maps_to_copy: # Note that 'map' is a Python keyword,
    # so it's best not to use it as a variable name here.
    shutil.copyfile(source_map_folder + map_for_site,
                    dest_map_folder + map_for_site)  
    

I could also have just copied and pasted these maps into my new folder, but this approach would save time in the long run if I happened to have lots of maps or made frequent updates to them. (Of course, if the updates were very frequent, a dynamic site could potentially be a better option than a static one.)

The maps will form the main content of our static site. However, we’ll also need a landing page that can introduce the content and direct visitors to each page.

The following cell shows the Markdown-formatted text that I wrote for this landing page. (You can also use HTML for this page, but Markdown is a bit simpler. If you’re not familiar with Markdown, check out Matt Cone’s handy introduction at https://www.markdownguide.org/basic-syntax/ .)

Note that the links to each map are relative, thus making them compatible within various repository names. (The links to the GitHub version of Python for Nonprofits, in contrast, are absolute.) Because the maps are located within a ‘maps/’ subfolder, I needed to incorporate that folder into these relative links.

# Selected output from the mapping section of Python for Nonprofits

By Kenneth Burchfiel

Released under the MIT License

This simple webpage provides links to six maps created within
the [Mapping](https://github.com/kburchfiel/pfn/tree/main/Mapping) section
of [Python for Nonprofits](https://github.com/kburchfiel/pfn). It is meant
to demonstrate how visualizations can be hosted within 
a static GitHub Pages website.

Python for Nonprofits, like this repository, is released under 
the MIT License.

## Population growth maps

These maps visualize population growth rates at the state and county
level **from 2011 to 2021.** They were created using the Plotly graphing
library within PFN's choropleth_maps.ipynb notebook, available at
https://github.com/kburchfiel/pfn/blob/main/Mapping/choropleth_maps.ipynb .

**Note: Certain maps will be easier to view on a laptop or monitor than
on your phone.**

### Total population growth

[State-level total population growth](maps/state_pop_pct_growth_2011-2021.html)

[County-level total population growth](maps/county_pop_pct_growth_2011-2021_tiled.html)

### Population growth for adults aged 25 to 29

[State-level 25-29 population growth](maps/state_25-29_pop_pct_growth_2011-2021.html)

[County-level 25-29 population growth](maps/county_25-29_pop_pct_growth_2011-2021_tiled.html)

## Net domestic migration maps

These maps show net domestic migration rates at the state and
county level **from April 1, 2020 to June 1, 2024**. They are based on
the Folium mapping library and were created within PFN's
'choropleth_maps_with_folium.ipynb' notebook, available at
https://github.com/kburchfiel/pfn/blob/main/Mapping/choropleth_maps_with_folium.ipynb .

[State-level net migration](maps/net_migration_rate_state_2020-2024.html)

[County-level net migration](maps/net_migration_rate_county_2020-2024.html)

I enclosed the above text within a code block so that you could see the actual markdown code being used. To see how this text will actually appear on the website, simply visit https://kburchfiel.github.io/simple_static_site/ .

I then saved this text into a new file within my simple_static_site folder called index.md . GitHub Pages will use this file to construct my site’s landing page.

The folder structure of my simple_static_site project is as follows:

simple_static_site/
----index.md
----maps/
--------county_25-29_pop_pct_growth_2011-2021_tiled.html
--------county_pop_pct_growth_2011-2021_tiled.html
--------net_migration_rate_county_2020-2024.html
--------net_migration_rate_state_2020-2024.html
--------state_25-29_pop_pct_growth_2011-2021.html
--------state_pop_pct_growth_2011-2021.html

As noted earlier, the ‘simple_static_site/’ folder should be located within the same folder as your Python for Nonprofits folder in order for the file transfer code shown above to work.

Publishing this static site via GitHub Pages#

I now have all the material I need for my site! My next step will be to export it to the GitHub repository that I created earlier. The steps for doing so via the command line are documented well on GitHub’s website, so review that documentation (available at https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github) if you ‘git’ stuck.

(You can also upload files directly to your GitHub page if you prefer. That approach should work fine for a simple static page like this one, but for more complex projects, you may find it easier to perform Git and GitHub operations via the command line.)

After uploading the content to GitHub, I went into my repository’s Settings page; navigated to Pages; and instructed GitHub to deploy my site from the root tab of my main branch. (The GitHub Pages documentation linked to earlier provides more details.)

Your site most likely will not appear right away; similarly, whenever you make updates to your online repository’s contents, it may take a little while for those updates to manifest. However, after a minute or two, the GitHub Pages tab within the Settings page informed me that “Your site is live at https://kburchfiel.github.io/simple_static_site/ .” Great–my maps are now available for anyone to view!

As you’ll see when navigating to the above link, this site is very simple indeed. The landing page has essentially no colors and no images. The HTML-based map pages to which it links are colorful and interactive, but they don’t offer any built-in navigation menus; to revisit the landing page, you’ll need to use your back button.

More advanced sites#

The method for deploying a static site that this notebook features should work fine when you just need to make static content (like maps–or HTML versions of Jupyter Notebooks) available online. However, I thought I would also list some more robust alternatives to this approach in case it doesn’t meet your own needs.

First, for more complex static sites, look into Jekyll (https://jekyllrb.com/docs/), the static site generator that GitHub Pages uses. (GitHub Pages-specific Jekyll instructions can be found at https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll , but you’ll likely find the Jekyll site to be helpful also.)

Jupyter Book (https://jupyterbook.org/en/stable/intro.html) is also worth looking into. Python for Nonprofits makes use of this tool to convert its many notebooks and markdown files into a PDF file that can serve as the basis for a printed book. This tool can also be used to generate static webpages, so consider using it if you too have a manual or book that you’d like to host online. (For more information on this functionality, see https://jupyterbook.org/en/stable/web/index.html .)

As of March 2025, GitHub Pages sites also can’t be made private unless you have an Enterprise License. Therefore, if you need to limit whom can see your site, consider using Google Sites (https://sites.google.com/), a free tool that allows you to share your content with only specific users (or just yourself). You can add full-screen interactive maps (and other visualizations) to Google Sites Pages via the ‘Full page embed’ option.

Finally, you may determine that a purely static site doesn’t meet your needs. In that case, stay tuned for the Online Visualizations section of Python for Nonprofits, where you’ll learn how to create dynamic Dash web apps that respond to user input.

In certain cases, you don’t actually need to share visualizations with end users: the underlying numbers themselves will be sufficient. Therefore, the next section of PFN will demonstrate how to publish data online via Google Sheets.