If you draw the horizontal lines after the bars (in the code/dom) they will show on top. (it's a bit hard to read the legend on the bottom one (i guess the one that says Norgespris)
Good point.
Want another tip? Since today is only the right 1/3 of the vis, it's probably a better idea to move the legend to the right. (the dates and colors). I would also align them horizontally instead of vertically, that way you avoid them overlapping your high price lines.
Finally, it's possible to add a little white outline to your text, that makes it a lot easier to read it against a striped background like you have (NYTimes does this a lot)
You might also want to take in some of the margin on the left side to move the price closer to axis label
Clean viz man!
Description
The below description is supplied in free-text by the user
#!/usr/bin/env python3
import argparse
import inspect
import json
from pathlib import Path
from datetime import datetime, timedelta
import sys
from novem import Plot
import pandas as pd
import requests
def fetch_electricity_prices(date, region="NO1"):
"""
Fetch electricity prices for a specific date in a Norwegian region.
Args:
date (datetime): Date to fetch prices for
region (str): Norwegian electricity region code (default: 'NO1')
Returns:
list: Formatted list of tuples with hour and price including MVA
"""
# Format date in required format (YYYY/MM-DD)
formatted_date = date.strftime("%Y/%m-%d")
# Construct the API URL
url = (
f"https://www.hvakosterstrommen.no/api/v1/prices/{formatted_date}_{region}.json"
)
try:
# Fetch data from API
response = requests.get(url, verify=False)
response.raise_for_status() # Raise exception for HTTP errors
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error fetching data for {formatted_date}: {e}", file=sys.stderr)
return []
def process_data(df: pd.DataFrame):
# Compute price incl. MVA tax rate in Norway (25%)
mva_rate = 0.25
df["NOK_per_kWh"] = (df["NOK_per_kWh"] * (1 + mva_rate)).round(4)
# Extract date and hour from time_start
df["date"] = pd.to_datetime(df["time_start"]).dt.date
df["hour"] = pd.to_datetime(df["time_start"]).dt.hour
return df.pivot_table(
index="date", columns="hour", values="NOK_per_kWh", aggfunc="first"
)
def parse_date(date_str):
if date_str.lower() == "today":
date = datetime.now()
elif date_str.lower() == "tomorrow":
date = datetime.now() + timedelta(days=1)
elif date_str.lower() == "yesterday":
date = datetime.now() - timedelta(days=1)
else:
date = datetime.strptime(date_str, "%Y-%m-%d")
return date.replace(hour=0, minute=0, second=0, microsecond=0)
def main(argv: list[str]):
parser = argparse.ArgumentParser(
description="Fetch and display Norwegian electricity prices for specified dates."
)
parser.add_argument(
"--fetch",
action="store_true",
help="Fetch and store API JSON data to files only.",
)
parser.add_argument(
"--load",
action="store_true",
help="Load data from local JSON files instead of fetching from API.",
)
parser.add_argument(
"--region",
type=str,
default="NO1",
help="Norwegian electricity region code (default: NO1).",
)
parser.add_argument(
"--plot",
type=str,
help="Name of novem plot to update.",
)
parser.add_argument(
"dates",
nargs="*",
help="Dates to fetch prices for (format: YYYY-MM-DD). Use 'today', 'tomorrow', or 'yesterday'. Default is today if no dates are provided.",
)
args = parser.parse_args(argv)
# Parse input dates
dates = [parse_date(date) for date in args.dates]
if not dates:
dates = [parse_date("today")]
if args.load:
data = []
for date in dates:
filename = Path(f"strompriser_{date.strftime('%Y-%m-%d')}_{args.region}.json")
if filename.exists():
json_data = json.loads(filename.read_text())
data.append(json_data)
else:
print(f"File {filename} not found. Skipping.", file=sys.stderr)
else:
data = [fetch_electricity_prices(date, args.region) for date in dates]
if args.fetch:
if args.load:
print("Cannot use --fetch and --load together.", file=sys.stderr)
return
for date, json_data in zip(dates, data):
filename = Path(f"strompriser_{date.strftime('%Y-%m-%d')}_{args.region}.json")
filename.write_text(json.dumps(json_data, indent=2))
print(f"Saved {filename}")
return
# Fetch prices for each date
prices = pd.concat(process_data(pd.DataFrame(d)) for d in data).transpose()
# Print csv results
if args.plot:
plt = Plot(args.plot)
plt.name = "Strømpriser i Norge"
plt.data = prices
plt.description = '\n'.join([
'```python',
inspect.getsource(sys.modules[__name__]),
'```',
])
else:
print(prices.to_csv(index_label="date"))
if __name__ == "__main__":
main(sys.argv[1:])