Chart a Repo's Star Growth
Build a chart that compares GitHub repository star growth over time.
Introduction
30 Second Summary
A repository's current star total shows where it stands today. That single number hides when momentum started or which project is gaining attention faster.
In this project, you will collect dated star counts from the GitHub REST API. You will shape those counts into a chart that compares the growth of two repositories.
What You'll Build
Your finished chart places two repositories on the same timeline, making the faster-growing project clear at a glance.
By the end of this project, you'll have:
- A dated star history table that reveals the earliest and latest data points returned for a repository.
- A reusable chart script that turns API data into a line chart image for any repository you choose.
- A two-repository comparison that places both growth curves on one plot. The steeper line shows which repository is growing faster.
- An optional Secret Mission to push your skills further.
Are there any prerequisites?
You'll need a GitHub account plus a personal access token.
You also need curl plus either Python or Node with a charting library. This project costs $0 to complete.
Before We Start
Star history only becomes useful after the request reaches your terminal. This setup step removes missing-tool surprises before you work with repository data.
You will use Python to shape the response. The curl command will retrieve it from GitHub.
In this step, get ready to:
- Verify Python 3, pip, curl, and a browser.
- Choose two public GitHub repositories for your chart.
- Confirm access to GitHub's personal access token settings.
Check your local tools
Each tool supports a different part of the project. Version output proves that your terminal can reach the tool when you need it.
macOS
- Press Cmd+Space to open your search bar.
- Search for your terminal application.
- Select the terminal application.
- Check Python, pip, and curl by running these commands:
python3 --version
python3 -m pip --version
curl --version
What do these checks prove?
- The first line confirms that the python3 command reaches Python 3.
- The second line confirms that pip belongs to the same Python installation.
- The third line confirms that curl can send the request later.
You should see three version outputs in your terminal.
Missing a version output?
Choose the matching outcome tab below to install the missing tool.
Help me diagnose my tool checks.
Windows
- Press the Windows key to open your search bar.
- Search for your terminal application.
- Select the terminal application.
- Check Python, pip, and curl by running these commands:
py --version
py -m pip --version
curl --version
What do these checks prove?
- The first line confirms that the py command reaches Python.
- The second line confirms that pip belongs to the same Python installation.
- The third line confirms that curl can send the request later.
You should see three version outputs in your terminal.
Missing a version output?
Choose the matching outcome tab below to install the missing tool.
Help me diagnose my tool checks.
- Match your terminal output to one of these setup paths.
✔️ I see three version outputs
Your local tools are ready. You now have the command-line foundation for the project.
ⓧ Python or pip is missing
Python includes the tools needed to run scripts. Its installer also provides a supported path for setting up pip.
- Open the official Python downloads page in your browser.
- Download the current Python 3 installer for your operating system.
- Run the installer.
- Complete the installation.
- Return to the terminal from earlier.
- Repeat the Python and pip checks from your platform tab.
Still missing Python or pip?
Your terminal may need a fresh session before it detects the installation.
Help me fix my Python installation.
ⓧ curl is missing
Curl sends requests from your terminal. The official download page points to packages for supported operating systems.
- Open the official curl download page in your browser.
- Select a curl package for your operating system.
- Follow the package provider's installation instructions.
- Return to the terminal from earlier.
- Repeat the curl check from your platform tab.
Still missing curl?
Your terminal may need a fresh session before it detects the installation.
Help me fix my curl installation.
Choose two public repositories
A repository path identifies its owner before the slash. The repository name comes after the slash.
How should the repository paths look?
Use OWNER/REPO for your primary repository. This format keeps the owner together with the repository name.
Use SECOND_OWNER/SECOND_REPO for the comparison repository. Both paths will feed the same script later.
- Open GitHub in your browser.
- Find a public repository with an established star count.
- Record its GitHub path here: OWNER/REPO.
- Keep the primary repository page open in a browser tab.
- Find a different public repository with an established star count.
- Record its GitHub path here: SECOND_OWNER/SECOND_REPO.
- Keep the comparison repository page open in a browser tab.
Confirm access to token settings
A personal access token authenticates requests to the GitHub API. You only confirm access here, so there is no secret to copy or store yet.
- Return to GitHub in your browser.
- Sign in to your GitHub account if prompted.
- Click your profile picture in the upper-right corner.
- Click Settings.
- Click Developer settings in the left sidebar.
- Click Fine-grained tokens under Personal access tokens.
- Confirm that Generate new token is visible.
Why stop on this page?
The visible token creation control proves that your account can begin the authentication setup. The next step handles the credential itself.
Before the final check, do you expect every tool plus both repository pages to be ready without another setup change?
- Return to your terminal.
- Repeat the three tool checks from your platform tab.
- Return to the page for OWNER/REPO.
- Confirm that the primary repository page loads.
- Return to the page for SECOND_OWNER/SECOND_REPO.
- Confirm that the comparison repository page loads.
- Return to your fine-grained token settings.
- Confirm that Generate new token remains visible.
You should see three version outputs in your terminal. Both public repository pages should load in your browser.
Your token settings should show Generate new token.
Your setup is ready for real star-history data. Next, you will create the credential for your first authenticated request.
Call the Star History API
Repository stars show interest, but a chart needs movement over time. The privacy-safe GitHub REST API returns historical counts without exposing individual stargazers.
In this step, you will create a narrowly scoped personal access token. You will use it in an authenticated curl request that prints timestamp-and-count JSON in the terminal.
In this step, get ready to:
- Create a fine-grained token for reading public repository data.
- Store the token only in the current terminal session.
- View the endpoint's timestamp-and-count JSON by sending an authenticated request.
Create a least-privilege token
A personal access token authenticates the request as you. Treat its value like a password because anyone holding it can use its granted access.
The token settings sit several levels deep, so the direct link saves some hunting. Public repositories already receive read-only access without extra permissions.
- Open the fine-grained token form in your browser.
- Enter repo-star-history in the Token name field.
- Choose a short expiration under Expiration.
- Select your GitHub account under Resource owner.
- Keep the default read-only access for public repositories under Repository access.
- Leave additional permissions unselected under Permissions.
- Click Generate token.
The generated token is now ready to copy. Keep it away from screenshots or project files.
- Copy the generated token using the copy icon beside it.
- Keep the browser page available until the token is stored in your terminal.
Store the token for this terminal session
An environment variable lets later commands use the token without placing its value inside the request. The value disappears when you close this terminal session.
Your token stays hidden while you paste it. This keeps the secret out of your terminal history.
- Start the hidden token prompt by running this command:
read -rs GITHUB_TOKEN && export GITHUB_TOKEN
What Does This Command Do?
- The read -rs command captures your input without displaying it.
- The export command makes GITHUB_TOKEN available to later commands in this terminal.
- The token remains in memory for the current terminal session.
- Paste the copied token into the waiting prompt.
- Press Enter to finish the command.
That sensitive part is handled. Your token is available to curl without appearing in terminal history or a project file.
Token Prompt Not Working?
- Run the command before pasting the token.
- Use a terminal profile that supports silent input if your shell rejects the command.
Get help with the terminal command by asking: Why is my terminal not storing the GitHub token in GITHUB_TOKEN?
Call the star history endpoint
The authorization header sends your token with the request. The endpoint uses your primary repository path to return its historical star data.
Before you run this, do you expect one current total or a series of values over time?
- Reuse your primary repository from earlier in this placeholder: OWNER/REPO.
- Send the authenticated request by running this command:
curl --request GET \
--url "https://api.github.com/repos/[[PRIMARY_REPOSITORY="OWNER/REPO"]]/stats/stars" \
--header "Authorization: Bearer $GITHUB_TOKEN"
What Does This Request Do?
- The curl command sends a GET request to GitHub.
- The Authorization header passes the token from GITHUB_TOKEN without printing its value.
- The URL targets the star history endpoint for your primary repository.
- Inspect the JSON printed beneath the command.
You will see a series of timestamp-and-count values for the repository. Those points provide the timeline that your chart uses later.
Response Not Showing Star History?
- Generate a fresh token if the response mentions an authentication problem.
- Repeat the hidden-input command to replace the current environment value.
- Check the spelling of the repository owner and name if the response says the resource is unavailable.
Get help without sharing your token by asking: Why is my authenticated GitHub star history request failing?
Your first star history response is in the terminal. Next, you will save that JSON before checking the date range it covers.
Save and Inspect Star Data
Your first GitHub REST API request proved that the endpoint can return star history. Now you will preserve that temporary terminal output as reusable data.
A local JSON file gives later steps a stable input. Inspecting its first and last entries reveals the available timestamp range before you start transforming the data.
In this step, get ready to:
- Save the primary repository response as repo1-stars.json.
- Print the first and last timestamp-and-star-count entries.
Keep the response beyond your terminal session
The response you viewed earlier only exists in your terminal scrollback. Saving the same request to repo1-stars.json creates the input that your parsing script can reuse.
- Replace OWNER/REPO in the command with your primary repository owner and name.
- Write the star history response to repo1-stars.json by running this command:
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2026-03-10" \
-o repo1-stars.json \
"https://api.github.com/repos/OWNER/REPO/stats/stars"
What does this command do?
- The headers authenticate the request with the token stored in GITHUB_TOKEN for the current terminal session.
- The output option writes the response into repo1-stars.json.
- The saved file preserves the ordered timestamp-and-count pairs for later parsing.
Good, the API response now lives beyond your terminal scrollback. Your reusable input is stored in repo1-stars.json.
File not saving?
- Check that OWNER/REPO matches the primary repository you selected.
- Confirm that GITHUB_TOKEN remains set in the terminal session from earlier.
Help me work out why the response is not being saved to repo1-stars.json.
Find the available range
Each saved data point contains two values. The first is a Unix timestamp. The second is the cumulative star count at that point.
- Before you run this, predict whether the first timestamp will be lower or higher than the last.
- Print the first and last entries from repo1-stars.json by running this command:
python3 -c 'import json; data = json.load(open("repo1-stars.json")); print("First:", data[0]); print("Last:", data[-1])'
How does the inspection work?
- The json.load() function reads the saved response into data.
- The data[0] expression selects the first entry.
- The data[-1] expression selects the last entry.
You will see two lines labeled First: and Last:. Each line contains a Unix timestamp followed by a cumulative star count.
You have pinned down the exact range that your future chart can honestly represent.
Entries not printing?
- Confirm that repo1-stars.json is saved in the terminal location you are currently using.
- Inspect the saved response for an API message if Python cannot select its first or last entry.
Help me diagnose why Python cannot print the first and last entries.
Your star history is saved with its boundaries confirmed. Next, you will turn those timestamps and counts into a readable table.
Build a Star Data Table
The saved GitHub response proves your request worked. Its Unix timestamps still hide the timeline you need for a chart.
Each JSON entry contains a timestamp beside a cumulative star count. A dated table turns those pairs into evidence you can read before you plot them.
In this step, get ready to:
- Load the saved star-history response with Python.
- Convert each timestamp into a readable date.
- Print a dated star-count table in your terminal.
Convert timestamps into dated entries
A dated series gives every cumulative star count a readable date. The same structure can feed the chart in the next step.
- Create star_growth.py beside repo1-stars.json by pasting the following code into a new file in your terminal editor:
import json
import datetime
def load_star_history(filename):
# Load the ordered timestamp and cumulative-count pairs.
with open(filename, "r") as file:
star_history = json.load(file)
# Give each count a UTC date that the table can display.
dated_series = []
for timestamp, stars in star_history:
dated_series.append({
"date": datetime.datetime.fromtimestamp(
timestamp, tz=datetime.timezone.utc
).date().isoformat(),
"stars": stars,
})
# Print every parsed point before the data reaches a chart.
print(f"{'Date':<12} {'Stars':>10}")
for entry in dated_series:
print(f"{entry['date']:<12} {entry['stars']:>10}")
return dated_series
dated_series = load_star_history("repo1-stars.json")
What does this code do?
- The load_star_history() function reads the saved response with json.load().
- The loop separates each entry into timestamp and stars values.
- The datetime conversion produces a UTC date in YYYY-MM-DD form.
- The final loop prints every date beside its cumulative stars value.
- Save star_growth.py in the same folder as repo1-stars.json.
✔️ Awesome, I've got everything!
Your saved script is ready to turn the response into a table.
ⓧ I'd like to double check the full code
import json
import datetime
def load_star_history(filename):
# Load the ordered timestamp and cumulative-count pairs.
with open(filename, "r") as file:
star_history = json.load(file)
# Give each count a UTC date that the table can display.
dated_series = []
for timestamp, stars in star_history:
dated_series.append({
"date": datetime.datetime.fromtimestamp(
timestamp, tz=datetime.timezone.utc
).date().isoformat(),
"stars": stars,
})
# Print every parsed point before the data reaches a chart.
print(f"{'Date':<12} {'Stars':>10}")
for entry in dated_series:
print(f"{entry['date']:<12} {entry['stars']:>10}")
return dated_series
dated_series = load_star_history("repo1-stars.json")
Run and review the table
Before you run the script, which parts of each raw entry do you expect to become the table's two columns?
- Run star_growth.py from the folder containing both files by using this command:
python3 star_growth.py
You will see a Date header beside a Stars header. Each later row will contain a date beside its cumulative star count.
- Compare the first table date with the first date you observed earlier.
- Compare the last table date with the last date you observed earlier.
- Scan the Stars column to confirm every date has a cumulative count.
That is your data pipeline working. The API response is now a readable series you can inspect before charting it.
Table missing or dates look wrong?
- Confirm star_growth.py sits in the same folder as repo1-stars.json.
- Check that the filename inside load_star_history() matches repo1-stars.json exactly.
- Compare the indentation inside both loops with the full-code reference.
Help me debug my star data table.
Your star history now has readable dates and counts. Next up, you will turn this table into a line chart you can open and inspect.
Render the Star Chart
Your parsed table now shows the GitHub star history in chronological order. Reading its overall growth shape row by row takes too much effort.
This step uses Matplotlib to turn dated_series into a labeled line chart. The saved image makes the repository's growth visible at a glance.
In this step, get ready to:
- Install Matplotlib for chart rendering.
- Draw a labeled line for the primary repository.
- Review the saved star-growth.png image.
Install Matplotlib
Your script already prepares the chart data. Matplotlib provides the plotting tools that turn those values into an image.
- Install Matplotlib into your Python 3 environment by running this command:
python3 -m pip install matplotlib
What does this command do?
Python runs pip as a module. Pip installs Matplotlib into the environment that runs your script.
- Wait for the installation command to finish.
You should see your terminal prompt return after the packages finish installing.
Matplotlib installation failed?
- Confirm the command begins with python3 so Matplotlib installs for the interpreter used by your script.
- Check your network connection if the package download stops.
Help me fix the Matplotlib installation.
Connect Matplotlib
Your script needs a plotting interface before it can draw. The plt alias keeps each chart command short.
- In star_growth.py, locate the existing imports at the top of the file.
- Add the plotting import directly below them:
# Add plotting tools for the chart
import matplotlib.pyplot as plt
What does this import do?
The import loads Matplotlib's plotting interface under the name plt. Your script uses that alias to draw the line.
- Save star_growth.py.
- Confirm the new import loads by running your script:
python3 star_growth.py
What does this run prove?
The script still loads repo1-stars.json before printing the dated star-count table.
Seeing that table confirms the new import loads successfully.
That clean table output confirms Matplotlib now loads beside your parser.
Script stops at the import?
- Check that the import reads import matplotlib.pyplot as plt.
- Run the installation command again with the same python3 interpreter.
Help me fix the Matplotlib import.
Render Star Growth
A line chart maps dates to horizontal positions. It maps cumulative star counts to height.
- In star_growth.py, move below the loop that prints the table.
- Add the chart block at the end of the file:
# Plot cumulative stars against each recorded date
plt.plot(
[point["date"] for point in dated_series],
[point["stars"] for point in dated_series],
label="OWNER/REPO",
)
# Label the chart so the saved image explains itself
plt.title("GitHub Star Growth")
plt.xlabel("Date")
plt.ylabel("Cumulative Stars")
plt.legend()
plt.tight_layout()
# Save the finished chart beside the script
plt.savefig("star-growth.png")
What does this code do?
- The plt.plot() call maps each date to its cumulative star count.
- The label value names the repository line.
- The title describes the chart's subject.
- The axis labels explain both scales.
- The plt.savefig() call writes the finished plot to star-growth.png.
- Save star_growth.py.
Before you run the script, what line shape do you expect from the repository's history?
- Generate the chart image by running your script:
python3 star_growth.py
What should happen?
Your dated table prints in the terminal again. The same parsed values now feed the chart.
The script saves star-growth.png beside star_growth.py.
Chart file missing?
- Check that plt.savefig("star-growth.png") remains at the bottom of star_growth.py.
- Confirm repo1-stars.json is still beside the script.
Help me debug my missing chart file.
- Open star-growth.png with your computer's default image app by using the command for your system:
macOS
- Open the chart from the current terminal folder by running this command:
open star-growth.png
What should I see?
macOS opens the chart with the default app associated with PNG images.
Windows
- Open the chart from the current PowerShell folder by running this command:
Start-Process -FilePath "star-growth.png"
What should I see?
Windows opens the chart with the default app associated with PNG images.
You should see a single line labeled OWNER/REPO. Its horizontal axis shows dates.
Its vertical axis shows cumulative stars. You have turned the API response into a reviewable chart.
✔️ Awesome, I've got everything!
Your script is saved. Your chart opens with the repository's dated star growth.
ⓧ I'd like to double check the full code
import json
from datetime import datetime
# Add plotting tools for the chart
import matplotlib.pyplot as plt
def load_star_history(filename):
# Load the ordered timestamp and cumulative star-count pairs
with open(filename, "r", encoding="utf-8") as file:
history = json.load(file)
# Convert timestamps into dated entries for display and plotting
return [
{
"date": datetime.fromtimestamp(timestamp).date(),
"stars": stars,
}
for timestamp, stars in history
]
dated_series = load_star_history("repo1-stars.json")
# Print a table that exposes the values behind the chart
print("Date\tStars")
for point in dated_series:
date = point["date"]
stars = point["stars"]
print(f"{date}\t{stars}")
# Plot cumulative stars against each recorded date
plt.plot(
[point["date"] for point in dated_series],
[point["stars"] for point in dated_series],
label="OWNER/REPO",
)
# Label the chart so the saved image explains itself
plt.title("GitHub Star Growth")
plt.xlabel("Date")
plt.ylabel("Cumulative Stars")
plt.legend()
plt.tight_layout()
# Save the finished chart beside the script
plt.savefig("star-growth.png")
Your primary repository now has a chart you can inspect. Next, you will add the second repository so both growth lines share one plot.
Compare Two Repositories
Your first GitHub repository now has a dated star-growth chart. A single line gives you no comparison point.
Now you'll fetch the second history. The same parser will turn both responses into comparable series.
In this step, get ready to:
- Save the second repository's star history as JSON.
- Print both dated tables plus their star-count changes.
- Compare repository growth through a two-line chart.
Download the second star history
A fair comparison starts with a second response saved in the same format as the first. Your existing parser can then process both files consistently.
- Replace SECOND_OWNER/SECOND_REPO in the command with your comparison repository's full owner and repository pair.
- Create repo2-stars.json by running these commands:
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-GitHub-Api-Version: 2026-03-10" \
"https://api.github.com/repos/SECOND_OWNER/SECOND_REPO/stats/stars" \
-o repo2-stars.json
ls repo2-stars.json
What does this command do?
The authenticated request saves the second repository's history in repo2-stars.json. Your token stays in GITHUB_TOKEN without being written to the file.
The final file listing confirms that repo2-stars.json exists in the current folder.
Second history not saved?
- Confirm that your comparison repository pair has the correct spelling.
- Check that the token remains available in the current terminal session.
- Make sure the selected repository is accessible with your token.
Help me diagnose why my second star history response was not saved.
Compare the dated star counts
Each response contains the same two-value data points. Loading both files through load_star_history() keeps the date conversion consistent.
- In star_growth.py, select every existing line after return dated_series.
- Replace the selected code with this comparison logic:
# Load both histories with the same parsing function.
repo1_series = load_star_history("repo1-stars.json")
repo2_series = load_star_history("repo2-stars.json")
# Print each dated table so the underlying points stay visible.
for label, dated_series in (
("OWNER/REPO", repo1_series),
("SECOND_OWNER/SECOND_REPO", repo2_series),
):
print(f"\n{label}")
print("Date\tStars")
for point in dated_series:
print(f"{point['date']}\t{point['stars']}")
# Compare cumulative growth across each available date range.
repo1_change = repo1_series[-1]["stars"] - repo1_series[0]["stars"]
repo2_change = repo2_series[-1]["stars"] - repo2_series[0]["stars"]
print(f"\nOWNER/REPO star-count change: {repo1_change}")
print(f"SECOND_OWNER/SECOND_REPO star-count change: {repo2_change}")
What does this code do?
- The repo1_series variable stores the parsed primary history.
- The repo2_series variable stores the parsed comparison history.
- The loop applies the same table layout to each repository.
- The subtraction measures the cumulative star-count change across each available date range.
Before you run the script, which repository do you expect to show the larger star-count change?
- Save star_growth.py.
- Print both tables plus their changes by running:
python3 star_growth.py
What should you see?
You'll see a dated star-count table for each repository. The repository labels separate the two tables.
Below the tables, you'll see one star-count change for each repository.
Script cannot read both histories?
- Check that repo1-stars.json remains in the same folder as star_growth.py.
- Check that repo2-stars.json is in that folder too.
- Compare both filenames with the names passed to load_star_history().
Help me find why star_growth.py cannot print both repository histories.
Draw the comparison chart
A shared set of axes makes the two trends visually comparable. Matplotlib uses a legend to keep each line tied to its repository.
- In star_growth.py, place your cursor after the final star-count change line.
- Add the two-line chart by pasting this code:
# Plot the primary repository as the first labeled line.
plt.plot(
[point["date"] for point in repo1_series],
[point["stars"] for point in repo1_series],
label="OWNER/REPO",
)
# Plot the comparison repository on the same axes.
plt.plot(
[point["date"] for point in repo2_series],
[point["stars"] for point in repo2_series],
label="SECOND_OWNER/SECOND_REPO",
)
# Label the shared chart and save the comparison image.
plt.title("GitHub Star Growth")
plt.xlabel("Date")
plt.ylabel("Cumulative stars")
plt.legend()
plt.tight_layout()
plt.savefig("star-growth.png")
How does the comparison work?
- The first plotting call draws the primary repository's dated counts.
- The second plotting call draws the comparison repository on the same axes.
- The legend maps each label to its plotted line.
- The final call replaces star-growth.png with the comparison chart.
Before you rebuild the chart, which repository do you expect to have the steeper trend?
- Save star_growth.py.
- Generate the updated comparison image by running:
python3 star_growth.py
What did the script update?
The script rebuilds star-growth.png with both dated series.
It also prints the tables plus their star-count changes again.
- Return to the browser tab that showed star-growth.png earlier.
- Refresh the page.
You'll see two labeled lines on one chart. The legend identifies the repository behind each trend.
Still seeing one line?
- Confirm that both plt.plot() calls remain in star_growth.py.
- Refresh the browser after rerunning the script.
- Check whether the two histories overlap closely across the displayed dates.
Help me diagnose why my comparison chart shows only one visible line.
- Compare the rise of each line across its displayed date range.
- Match each line to its printed star-count change through the legend.
- Identify the repository whose evidence indicates faster growth.
✔️ Awesome, I've got everything!
Your script now loads both histories. It prints both tables before drawing the comparison chart.
ⓧ I'd like to double check the full code
Compare your saved star_growth.py with this complete version.
import json
from datetime import datetime
import matplotlib.pyplot as plt
def load_star_history(filename):
# Read the saved API response from disk.
with open(filename, "r") as file:
star_history = json.load(file)
# Convert each timestamp and count into a named data point.
dated_series = []
for timestamp, stars in star_history:
dated_series.append(
{
"date": datetime.fromtimestamp(timestamp).date(),
"stars": stars,
}
)
return dated_series
# Load both histories with the same parsing function.
repo1_series = load_star_history("repo1-stars.json")
repo2_series = load_star_history("repo2-stars.json")
# Print each dated table so the underlying points stay visible.
for label, dated_series in (
("OWNER/REPO", repo1_series),
("SECOND_OWNER/SECOND_REPO", repo2_series),
):
print(f"\n{label}")
print("Date\tStars")
for point in dated_series:
print(f"{point['date']}\t{point['stars']}")
# Compare cumulative growth across each available date range.
repo1_change = repo1_series[-1]["stars"] - repo1_series[0]["stars"]
repo2_change = repo2_series[-1]["stars"] - repo2_series[0]["stars"]
print(f"\nOWNER/REPO star-count change: {repo1_change}")
print(f"SECOND_OWNER/SECOND_REPO star-count change: {repo2_change}")
# Plot the primary repository as the first labeled line.
plt.plot(
[point["date"] for point in repo1_series],
[point["stars"] for point in repo1_series],
label="OWNER/REPO",
)
# Plot the comparison repository on the same axes.
plt.plot(
[point["date"] for point in repo2_series],
[point["stars"] for point in repo2_series],
label="SECOND_OWNER/SECOND_REPO",
)
# Label the shared chart and save the comparison image.
plt.title("GitHub Star Growth")
plt.xlabel("Date")
plt.ylabel("Cumulative stars")
plt.legend()
plt.tight_layout()
plt.savefig("star-growth.png")
You've got the full comparison working. Your chart now turns two API responses into evidence you can read at a glance.
Secret mission
Audit the Growth Comparison
Audit the existing two-repository chart over the dates both repositories share. Decide whether your faster-growth verdict still holds across an equal time window.
Clean Up Your Resources
Clean Up Your Resources
Your Python chart files run locally, so they create no ongoing costs. The GitHub REST API requests in this project also cost $0.
Resources you used:
- GitHub personal access token stored in GITHUB_TOKEN.
- Primary star history response for OWNER/REPO in repo1-stars.json.
- Comparison star history response for SECOND_OWNER/SECOND_REPO in repo2-stars.json.
- Reusable charting script in star_growth.py.
- Two-line comparison chart in star-growth.png.
Keep everything running
No action needed. Choose this if you are still comparing repositories or refining the chart.
- Keep star_growth.py, repo1-stars.json, repo2-stars.json, and star-growth.png together in their current folder.
- Keep the personal access token active only while you are making star history requests.
- Use the Delete tab after your final request to revoke the token.
Pause - I'll come back to this later
Pausing preserves your reusable files. It also closes the credential before you step away.
- Return to the GitHub token settings you used to create the personal access token.
- Find the token created for OWNER/REPO and SECOND_OWNER/SECOND_REPO.
- Revoke that token.
- Close the terminal window from earlier to clear GITHUB_TOKEN from the session.
- Confirm star_growth.py, repo1-stars.json, repo2-stars.json, and star-growth.png remain in their current folder.
That closes the token's access safely. Your script and chart remain ready for another comparison.
Delete - I don't want to use this again
Remove the credential and all local artifacts if you are finished with the comparison. Revoking the token ends its access without changing your local files.
- Return to the GitHub token settings you used to create the personal access token.
- Find the token created for OWNER/REPO and SECOND_OWNER/SECOND_REPO.
- Revoke that token.
- Confirm the token is removed from the token settings page.
- Close the terminal window from earlier to clear GITHUB_TOKEN from the session.
That's the account access closed safely. The remaining cleanup removes only the four project files you created.
- Use your operating system's search to open its file browser.
- Open the same folder where you saved star_growth.py.
- Select star_growth.py, repo1-stars.json, repo2-stars.json, and star-growth.png.
- Use the file browser's delete action to remove the selected files.
- Remove the same four files from your operating system's deleted-items area.
- Confirm the original folder no longer contains any of the four project files.
You're all clear. The personal access token and local project artifacts are gone.
Nice Work!
Nice Work!
You did it! Your Python workflow now turns star-history data from the GitHub REST API into a two-repository comparison chart.
You've learned how to:
- Pulled privacy-safe star history for two public repositories. Saved each response as a JSON file without collecting stargazer identities.
- Converted ordered timestamps into dates with star_growth.py. Printed each dated series as a table to expose the available date range.
- Rendered a two-line comparison chart with Matplotlib. Used star-growth.png to identify which repository was growing faster.
- Secret Mission: Put your new repository-growth analysis skills through an optional challenge.
Ready to quiz yourself?