Created
January 9, 2024 23:53
-
-
Save kenielf/3c39f3b826ced90adda8ba6f0c283e12 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pathlib import Path | |
from re import sub | |
from sys import exit, stderr | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
from colorama import Fore | |
from requests import get | |
CWD = Path(__file__).parent | |
URL = r"https://www.cpc.ncep.noaa.gov/data/indices/sstoi.indices" | |
DATA_FILE = CWD / "data.csv" | |
DATA_DETAILS = { | |
'ANOM': { | |
"linestyle": "solid", | |
"color": "red", | |
}, | |
'ANOM.1': { | |
"linestyle": "dashed", | |
"color": "green", | |
}, | |
'ANOM.2': { | |
"linestyle": "dotted", | |
"color": "blue", | |
}, | |
'ANOM.3': { | |
"linestyle": "dashdot", | |
"color": "orange", | |
}, | |
} | |
DATA_RANGE = [ | |
2.5, 2.0, 1.5, 1.0, 0.5, 0.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0 | |
] | |
PLOT_DIR = CWD / "plots" | |
PLOT_DIR.mkdir(parents=True, exist_ok=True) | |
def info(message: str) -> None: | |
print(f"{Fore.CYAN}Info:{Fore.RESET} {message}") | |
def render_plot(year: int, raw_data: pd.DataFrame): | |
info("Rendering plot...") | |
# Clear previous plots | |
plt.cla() | |
# Set basic plot attributes | |
plt.grid() | |
plt.tight_layout() | |
# Isolate data | |
regions = DATA_DETAILS.keys() | |
data = raw_data[['MON', *DATA_DETAILS]] | |
print(data) | |
# Render data | |
for region in regions: | |
x = data['MON'] | |
y = data[region] | |
# Lines | |
plt.plot( | |
x, | |
y, | |
lw=1, | |
linestyle=DATA_DETAILS[region]['linestyle'], | |
color=DATA_DETAILS[region]['color'], | |
marker='.', | |
markersize=5, | |
label=region | |
) | |
# Annotations | |
for pos in x.index: | |
plt.annotate(str(y[pos]), (x[pos], y[pos])) | |
plt.legend() | |
# Set advanced plot attributes | |
plt.title(f"{year} Anomalies") | |
plt.xticks(data['MON']) | |
plt.yticks(DATA_RANGE) | |
# Save figure | |
plt.savefig(PLOT_DIR / f"anomaly-{year}.png") | |
if __name__ == "__main__": | |
# If the data file does not exist, download it | |
if not DATA_FILE.exists(): | |
print(f"{Fore.CYAN}Downloading data from source!{Fore.RESET}") | |
html = get(URL) | |
# Safety checks | |
if html.status_code != 200: | |
print(f"{Fore.RED}Error:{Fore.RESET} Failed to download page!", file=stderr) | |
exit(1) | |
# Write the file | |
with open(DATA_FILE, "w") as file: | |
cleaned = ( | |
sub(r"\s+", r",", str(html.content)) | |
.replace(r"\n", "\n") | |
.lstrip(r"b'") | |
.rstrip("'") | |
) # Clean formatting | |
file.write(cleaned) | |
# Read the data | |
print(f"{Fore.CYAN}Parsing data!{Fore.RESET}") | |
df = pd.read_csv(DATA_FILE) | |
# Print the whole table with pandas | |
# with pd.option_context( | |
# "display.max_rows", None, "display.max_columns", None, "display.precision", 3 | |
# ): | |
# print(df) | |
# Print pandas table from range | |
_range = df[(df["YR"] >= 2015) & (df["YR"] <= 2022)] | |
print(_range.to_string()) | |
_range.to_csv(Path(__file__).parent / "range.csv", encoding='utf-8', index=False) | |
df = pd.read_csv('range.csv') | |
# Configure Matplotlib | |
print(f"{Fore.CYAN}Plotting data...{Fore.RESET}") | |
plt.rcParams["figure.figsize"] = (7.50, 3.50) | |
plt.rcParams["figure.autolayout"] = True | |
headers = ['MON', 'ANOM', 'ANOM.1', 'ANOM.2', 'ANOM.3'] | |
## Plot the actual data | |
#data = [ | |
# df['ANOM'], | |
# df['ANOM.1'], | |
# df['ANOM.2'], | |
# df['ANOM.3'], | |
#] | |
##for column in data: | |
## ax = plt.plot(column, lw=2, marker='.', markersize=10) | |
#plt.plot(data) | |
#plt.xticks(df['MON']) | |
# Test 2 | |
#years = df.groupby(['YR']).mean() | |
## Print average of each value per year | |
#for column in years[['ANOM', 'ANOM.1', 'ANOM.2', 'ANOM.3']]: | |
# plt.plot(years['MON'], years[column], lw=1, marker='.', markersize=10) | |
## show | |
#plt.title("Average of each value") | |
#plt.grid() | |
#plt.tight_layout() | |
#plt.xticks(years['MON']) | |
#plt.yticks([2.5, 2.0, 1.5, 1.0, 0.5, 0.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0]) | |
#plt.show() | |
# NOTE: THIS WORKED! | |
#### Test 1 | |
###year_shit = df.loc[(df['YR'] == 2020)] | |
###year_shit = year_shit[['MON', 'ANOM', 'ANOM.1', 'ANOM.2', 'ANOM.3']] | |
###print(year_shit) | |
####data = [ | |
#### year_shit['ANOM'], | |
#### year_shit['ANOM.1'], | |
#### year_shit['ANOM.2'], | |
#### year_shit['ANOM.3'], | |
####] | |
###line_styles = { | |
### 'ANOM': 'solid', | |
### 'ANOM.1': 'dotted', | |
### 'ANOM.2': 'dashed', | |
### 'ANOM.3': 'dashdot', | |
###} | |
###colors = { | |
### 'ANOM': 'red', | |
### 'ANOM.1': 'blue', | |
### 'ANOM.2': 'green', | |
### 'ANOM.3': 'orange', | |
###} | |
###for column in year_shit[['ANOM', 'ANOM.1', 'ANOM.2', 'ANOM.3']]: | |
### x = year_shit['MON'] | |
### y = year_shit[column] | |
### plt.plot( | |
### x, | |
### y, | |
### lw=1, | |
### linestyle=line_styles[column], | |
### color=colors[column], | |
### marker='.', | |
### markersize=10, | |
### label=column | |
### ) | |
### # annotations | |
### for pos in x.index: | |
### plt.annotate(str(y[pos]), (x[pos], y[pos])) | |
### plt.legend() | |
#### X, Y ticks | |
###plt.title("2020 Anomalies") | |
###plt.grid() | |
###plt.tight_layout() | |
###plt.xticks(year_shit['MON']) | |
###plt.yticks([2.5, 2.0, 1.5, 1.0, 0.5, 0.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0]) | |
##### Display it | |
###plt.show() | |
# test 3 - Plot anomalies for each individual year | |
info("Plotting year anomalies...") | |
year_begin = 2015 | |
year_end = 2022 | |
for year in range(year_begin, year_end + 1): | |
print(f"{Fore.BLUE}Year: {Fore.RESET}{year}") | |
data: pd.DataFrame = df.loc[df['YR'] == year] | |
print(data) | |
render_plot(year, data) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment