Everyone who has used Matplotlib knows how ugly the default plots look. In this series of posts, I'll share some tricks to make your visualizations stand out and reflect your individual style.
We'll start with a simple line chart, which is widely used. The highlight will be adding a gradient fill below the graphic, a task that is not entirely simple.
So, let's dive in and review all the key steps of this transformation!
First let's do all the necessary imports.
import pandas as pd
import numpy as np
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import rcParams
from matplotlib.path import Path
from matplotlib.patches import PathPatchnp.random.seed(38)
Now we need to generate sample data for our visualization. We'll create something similar to what stock prices look like.
dates = pd.date_range(start='2024-02-01', periods=100, freq='D')
initial_rate = 75
drift = 0.003
volatility = 0.1
returns = np.random.normal(drift, volatility, len(dates))
rates = initial_rate * np.cumprod(1 + returns)x, y = dates, rates
Let's see what it looks like with the default Matplotlib settings.
fix, ax = plt.subplots(figsize=(8, 4))
ax.plot(dates, rates)
ax.xaxis.set_major_locator(mdates.DayLocator(interval=30))
plt.show()
It's not really fascination, is it? But little by little we will make it look better.
- set title
- set general chart parameters: size and font
- placing the Y marks on the right
- change the color, style and width of the main line
# General parameters
fig, ax = plt.subplots(figsize=(10, 6))
plt.title("Daily visitors", fontsize=18, color="black")
rcParams('font.family') = 'DejaVu Sans'
rcParams('font.size') = 14# Axis Y to the right
ax.yaxis.tick_right()
ax.yaxis.set_label_position("right")
# Plotting main line
ax.plot(dates, rates, color='#268358', linewidth=2)
Okay, now it looks a little cleaner.
Now we would like to add a minimalist grid to the background, remove borders for a cleaner look, and remove ticks from the Y axis.
# Grid
ax.grid(color="gray", linestyle=(0, (10, 10)), linewidth=0.5, alpha=0.6)
ax.tick_params(axis="x", colors="black")
ax.tick_params(axis="y", left=False, labelleft=False) # Borders
ax.spines("top").set_visible(False)
ax.spines('right').set_visible(False)
ax.spines("bottom").set_color("black")
ax.spines('left').set_color('white')
ax.spines('left').set_linewidth(1)
# Remove ticks from axis Y
ax.tick_params(axis='y', length=0)
Now we're adding an aesthetic detail: the year near the first tick on the x axis. We're also making the font color of the tick labels paler.
# Add year to the first date on the axis
def custom_date_formatter(t, pos, dates, x_interval):
date = dates(pos*x_interval)
if pos == 0:
return date.strftime('%d %b \'%y')
else:
return date.strftime('%d %b')
ax.xaxis.set_major_formatter(ticker.FuncFormatter((lambda x, pos: custom_date_formatter(x, pos, dates=dates, x_interval=x_interval))))# Ticks label color
(t.set_color('#808079') for t in ax.yaxis.get_ticklabels())
(t.set_color('#808079') for t in ax.xaxis.get_ticklabels())
And we are approaching the most complicated moment: how to create a gradient under the curve. Actually, there is no such option in Matplotlib, but we can simulate it by creating a gradient image and then clipping it with the plot.
# Gradient
numeric_x = np.array((i for i in range(len(x))))
numeric_x_patch = np.append(numeric_x, max(numeric_x))
numeric_x_patch = np.append(numeric_x_patch(0), numeric_x_patch)
y_patch = np.append(y, 0)
y_patch = np.append(0, y_patch)path = Path(np.array((numeric_x_patch, y_patch)).transpose())
patch = PathPatch(path, facecolor='none')
plt.gca().add_patch(patch)
ax.imshow(numeric_x.reshape(len(numeric_x), 1), interpolation="bicubic",
cmap=plt.cm.Greens,
origin='lower',
alpha=0.3,
extent=(min(numeric_x), max(numeric_x), min(y_patch), max(y_patch) * 1.2),
aspect="auto", clip_path=patch, clip_on=True)
Now it looks clean and pretty. We just need to add several details using any editor (I prefer Google Slides): title, rounded corners and some numerical indicators.
The full code to reproduce the visualization is below: