I have a series of datasets that I have to create a line graph for. I created a function that takes a df containing the data, a date to indicate the vertical line for "Inception date", and the dir where to save the created graph.
The issue I am having is that for the line graph, I can't seem to properly add yticks to display evenly and beyond the last data point. I also want the ytick values to be rounded to the tens value.
This is what I have tried:
np.arange()
but it didn't work well. The range of the data varies based on the dataset and I couldn't figure this one out.nbins=7
to see how it looks. I can't figure out how to make the nbins value dynamic so that the bins are evenly distributed over the y axis.Here is my function:
def build_multiple_line_graphs(df, inception_date, line_graph_path):
"""Builds line graphs for market data."""
# adjust this line to your local folder path
os.makedirs(line_graph_path, exist_ok=True)
inception_date = datetime.strptime(inception_date, '%Y-%m-%d')
# Plot the time series
fig, ax = plt.subplots()
# setting the size of the line graph
dpi=150
desired_width_pixels = 563
desired_height_pixels = 169
fig.set_size_inches(desired_width_pixels / dpi, desired_height_pixels / dpi)
fig.tight_layout()
df.plot(kind = 'line', ax=ax, y=complex, color='#0092BC')
# Add a horizontal line at y=0
ax.axhline(y=0, color='#005871', linestyle='-', label='Horizontal Line')
# Set the background color
ax.set_facecolor('#F0F8FF')
fig.patch.set_facecolor('#e4f2ff')
# removing frame from the graph
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
# set custom y-axis label
max_y = max(df)
if max_y < 1000:
max_y = 100*math.ceil(round(max_y/100)) if max_y > 0 else 1
else:
max_y = round((1000*math.ceil(max_y/1000))) if max_y > 0 else 1
new_max_y = max_y + (max_y//3)
increment = round(max_y/5)
ax.set_yticks(np.arange(0, max_y, increment))
plt.locator_params(axis='y', nbins=7)
# here is where I tried np.arange with no success
#ax.yaxis.set_major_locator(ticker.MultipleLocator(increment))
#ax.set_yticks(np.arange(0,df+1, increment))
#plt.yticks(np.arange(0,max(df)+increment, increment))
#start, end = ax.get_ylim()
#stepsize = end/5
#ax.yaxis.set_ticks(np.arange(0, end+1, 100))
ax.set_ylim(ymin=0)
# set custom x-axis label every 5 years
ax.xaxis.set_major_locator(mdates.YearLocator(5))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
plt.xticks(rotation=0, ha='center')
ax.grid(axis='y', color='gray')
# Customize the plot
ax.legend().remove()
ax.tick_params(axis='both', labelsize=8, left = False, bottom = False)
ax.set_xlabel(None)
ax.fill_between(df.index, df, 0, color='#FFFFFF', alpha=0.8)
ax.set_xlim(df.index[0], df.index[-1])
# formating the inception line
ax.axvline(inception_date, color = '#0092BC', linestyle='dotted', label='Inception Date')
ax.text(inception_date, 25, 'Inception Date', rotation=90, rotation_mode='anchor', transform_rotates_text= True, fontsize=6)
inception_date_text = inception_date.strftime("%m/%d/%y")
ax.annotate(inception_date_text, xy=(inception_date, -1), xytext=(-15, -18), fontsize=8,
textcoords='offset points', ha='center', va='bottom')
# saving the plot
plt.gcf() # get current figure
fig_size = plt.gcf().get_size_inches()
plt.gcf().set_size_inches(fig_size[0]*2, fig_size[1]*2)
plt.savefig(os.path.join(line_graph_path, 'name_linegraph.png'), bbox_inches='tight',dpi=300)
# no display of the plot needed
plt.close()
The Inception date in this example is 2024-08-23.
Here are the libraries I used:
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as ticker
import os
from datetime import datetime, timedelta
from datetime import *
import math
You were almost there. Just add +1 on this line:
ax.set_yticks(np.arange(0, max_y + 1, increment))