pythonpython-3.xmatplotlibhistogram

How can I create two 2D Histograms in a single figure with one colorbar?


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)


Solution

  • You are mixing the two different approaches for creating figures using matplotlib:

    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()
    

    enter image description here

    A couple of important points: