I am looking to create a figure that has has two 2D histograms in a row with a single colorbar. I can create each 2D histogram individually, but when I attempt to put them side by side things go haywire. I'm guessing I am missing something with matplotlib's subplot functionality.
I am reading the data from a csv file then looking to plot a specific value against the day of the week and week of the year to see changes over time. I would like to have two 2D histograms side by side to see the differences between two values and how they change over the course of a year.
I was expecting the 2D histograms to be side by side. Instead the left spot is blank and the right spot has the histogram I was expecting on the left side.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from datetime import datetime
xlabels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
ylabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
df=pd.read_csv("Mod4Data.csv", nrows = 366)
# Convert the day column into a date, month, day of week, and week of year
df["Date"]=df["Day"].apply(pd.to_datetime)
df["Day of Week"]=df["Date"].dt.dayofweek
df['week_of_year'] = df['Date'].dt.strftime('%W')
df['Month'] = df['Date'].dt.month
##Convert string data to floats
df['Value1'] = df['Value1'].astype(float)
df['Value2'] = df['Value2'].astype(float)
df['week_of_year'] = df['week_of_year'].astype(float)
fig, axs = plt.subplots(1, 2, figsize=(18, 10))
axs[0] = plt.hist2d(df["Day of Week"],
df["week_of_year"],
bins=[7,52],
weights=df["Value1"], vmin = 1000, vmax=20000)
plt.title("Value 1 Amounts")
plt.yticks([2, 6.3348, 10.66, 14.99, 19.32, 23.65, 27.98, 32.31, 36.64, 40.97, 45.3, 49.63], ylabels)
plt.xticks([0, 1, 2, 3, 4, 5, 6], xlabels, rotation = 45)
ax2 = plt.hist2d(df["Day of Week"],
df["week_of_year"],
bins=[7,52],
weights=df["Value2"], vmin = 1000, vmax=20000)
plt.title("Value 2 Amounts")
plt.yticks([2, 6.3348, 10.66, 14.99, 19.32, 23.65, 27.98, 32.31, 36.64, 40.97, 45.3, 49.63], ylabels)
plt.xticks([0, 1, 2, 3, 4, 5, 6], xlabels, rotation = 45)
You are mixing the two different approaches for creating figures using matplotlib
:
the explicit "Axes" interface
the implicit `pyplot` interface
I strongly suggest you read this page, as well as the rest of the matplotlib tutorial. Basically, the explicit gives you more control but will often make your code longer, while the other is often shorter but gives you less control. They can be mixed, but some rules have to be followed, see again the page linked above.
In your case, adapting this exemple for the matplotlib documentation gives:
import matplotlib.pyplot as plt
import numpy a
s np
from matplotlib.colors import Normalize
from numpy.random import multivariate_normal
# #### Generating data
# Fixing random state for reproducibility.
np.random.seed(19680801)
data1 = np.vstack(
[
multivariate_normal([10, 10], [[3, 2], [2, 3]], size=100000),
multivariate_normal([30, 20], [[3, 1], [1, 3]], size=1000),
]
)
data2 = np.vstack(
[
multivariate_normal([20, 20], [[3, 2], [2, 3]], size=100000),
multivariate_normal([20, 20], [[3, 1], [1, 3]], size=1000),
]
)
# #### making the figure
norm = Normalize(vmin=0, vmax=600)
fig, axs = plt.subplots(nrows=1, ncols=2, layout="constrained")
_, _, _, im1 = axs[0].hist2d(data1[:, 0], data1[:, 1], bins=100, norm=norm)
_, _, _, im2 = axs[1].hist2d(data1[:, 0], data1[:, 1], bins=100, norm=norm)
plt.colorbar(im2, ax=axs, location="top")
plt.show()
A couple of important points:
The colorbar function requires a mappable
, as mentioned in its documentation. In the case of hist2d
, it is the last element returned by the function.
The colorbar can be drawn only from a single mappable
. If you want to share the colorbar with different plot, you have to be sure that the colors are mapped with respect to the number the same way in the different plot. A nice way to do this is to use the same norm
in every plot. See here for more info.