I have a dataframe where each column contains values considered "normal" if they fall within an interval, which is different for every column:
# The main dfdf = pd.DataFrame({"A": [20, 10, 7, 39], "B": [1, 8, 12, 9], "C": [780, 800, 1200, 250]})
The df_info
represents the intervals for each column of df
.So for example df_info["A"][0]
is the min for the column df["A"]
and df_info["A"][1]
represents the max for the column df["A"]
and so on.
df_info = pd.DataFrame({"A": [22, 35], "B": [5, 10], "C": [850, 900]})
Thanks to this SO Answer I was able to create a custom heatmap to print in blue values below the range, in red value above the range and in white values within the range. Just remember each column has a different range. SO i normalized according to this:
df_norm = pd.DataFrame()for col in df: col_min = df_info[col][0] col_max = df_info[col][1] df_norm[col] = (df[col] - col_min) / (col_max - col_min)
And finally printed my heatmap
vmin = df_norm.min().min()vmax = df_norm.max().max()norm_zero = (0 - vmin) / (vmax - vmin)norm_one = (1 - vmin) / (vmax - vmin)colors = [[0, 'darkblue'], [norm_zero, 'white'], [norm_one, 'white'], [1, 'darkred'] ]cmap = LinearSegmentedColormap.from_list('', colors, )fig, ax = plt.subplots()ax=sns.heatmap(data=data, annot=True, annot_kws={'size': 'large'}, mask=None, cmap=cmap, vmin=vmin, vmax=vmax) \ .set_facecolor('white')
In the example you can see that the third column has values much higher/lower compared to the the 0-1
interval (and to the first column) so they "absorb" all the shades of red and blue.
QUESTION:What I want to obtain is use the entire shades of red/blue for each column or at least to reduce the perceptual difference between (for example) the first and third column.
I had tough of:
- create a custom colormap where each colormap normalization is performed by column
- use multiple colormaps, each one applied to a different column
- applying a colormap
mpl.colors.LogNorm
but I'm not sure how to use it with my customLinearSegmentedColormap