I have a few Pandas DataFrames sharing the same value scale, but having different columns and indices. When invoking df.plot()
, I get separate plot images. what
Assumptions
cat
, may be overlapping, but all dataframes may not contain all values of cat
hue='cat'
Because dataframes are being iterated through, there's not guarantee that colors will be mapped the same for each plot
'cat'
values for all the dataframesimport pandas as pd
import numpy as np # used for random data
import random # used for random data
import matplotlib.pyplot as plt
from matplotlib.patches import Patch # for custom legend
import seaborn as sns
import math import ceil # determine correct number of subplot
# synthetic data
df_dict = dict()
for i in range(1, 7):
np.random.seed(i)
random.seed(i)
data_length = 100
data = {'cat': [random.choice(['A', 'B', 'C']) for _ in range(data_length)],
'x': np.random.rand(data_length),
'y': np.random.rand(data_length)}
df_dict[i] = pd.DataFrame(data)
# display(df_dict[1].head())
cat x y
0 A 0.417022 0.326645
1 C 0.720324 0.527058
2 A 0.000114 0.885942
3 B 0.302333 0.357270
4 A 0.146756 0.908535
# create color mapping based on all unique values of cat
unique_cat = {cat for v in df_dict.values() for cat in v.cat.unique()} # get unique cats
colors = sns.color_palette('husl', n_colors=len(unique_cat)) # get a number of colors
cmap = dict(zip(unique_cat, colors)) # zip values to colors
# iterate through dictionary and plot
col_nums = 3 # how many plots per row
row_nums = math.ceil(len(df_dict) / col_nums) # how many rows of plots
plt.figure(figsize=(10, 5)) # change the figure size as needed
for i, (k, v) in enumerate(df_dict.items(), 1):
plt.subplot(row_nums, col_nums, i) # create subplots
p = sns.scatterplot(data=v, x='x', y='y', hue='cat', palette=cmap)
p.legend_.remove() # remove the individual plot legends
plt.title(f'DataFrame: {k}')
plt.tight_layout()
# create legend from cmap
patches = [Patch(color=v, label=k) for k, v in cmap.items()]
# place legend outside of plot; change the right bbox value to move the legend up or down
plt.legend(handles=patches, bbox_to_anchor=(1.06, 1.2), loc='center left', borderaxespad=0)
plt.show()