Skip to content

Instantly share code, notes, and snippets.

@kenielf
Created January 9, 2024 23:53
Show Gist options
  • Save kenielf/3c39f3b826ced90adda8ba6f0c283e12 to your computer and use it in GitHub Desktop.
Save kenielf/3c39f3b826ced90adda8ba6f0c283e12 to your computer and use it in GitHub Desktop.
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