Subplots Overlapping in "Annotated Heatmap"

Hi,

I created a graph with 4 subplots.
The main one (row = 1, column = 1) and the others totaling lines and columns.

However, there is an overlap between the main graph (row = 1, column = 1) and the graph that totals the lines (row = 1, column = 2).
Also, because of this, the “shared_yaxes” and “shared_yaxes” function does not work properly.

Does anyone know where I’m going wrong !?
I’ve tried several things. it is always the main graph (row = 1, column = 1), which gives an error.
I already tried to invert the orders of the graphs, adjust specs…

import os
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.figure_factory as ff
from plotly.subplots import make_subplots

# READ DATA
df = pd.read_csv(
    'https://raw.githubusercontent.com/michelmetran/pl251/main/data/tabs/tab_municipio_allinfos.csv',
)

# HOVER TEXT
class_1 = 'nome_rm'
class_2 = 'unidade'

list_class_1 = list(set(df[class_1]))
list_class_1.sort()
list_class_2 = list(set(df[class_2]))
list_class_2.sort()

list_class = []
for i in list_class_1:
    #print('Para a {} "{}" temos:'.format(class_1, i))
    df_temp = df[df[class_1] == i].copy()
    list_subclass = []
    for j in list_class_2:
        #print('Na {} "{}"'.format(class_2, j))
        df_temp2 = df_temp[df_temp[class_2] == j].copy()
        list_mun = list(df_temp2['municipio_nome'])
        if len(list_mun) == 0:
            list_text = ''
            list_subclass.append(list_text)
        elif len(list_mun) != 0:
            list_mun.sort()
            list_text = '<br>'.join(list_mun)
            #print('> {}'.format(list_text))
            list_subclass.append(list_text)
    list_class.append(list_subclass)

# ADJUST DATA
# Convert to Array
df_array = df.groupby(by=['nome_rm'])['unidade'].value_counts().sort_index()
df_array = df_array.unstack()
print(df_array)

# Principal Data
data_1 = df_array.replace(np.nan, 0, regex=True).to_numpy()
data_1 = data_1.astype(np.int64)
data_2 = np.array([int(i) for i in list(df_array.sum(axis=1))])
data_2 = np.reshape(data_2, (1, len(df_array))).T
data_3 = np.array([int(i) for i in list(df_array.sum(axis=0))])
data_3 = np.reshape(data_3, (1, len(df_array.columns)))
data_4 = np.array([[data_3.sum()]])

# Labels
x_label = list(df_array.columns)
y_label = list(df_array.index)

# Invert Matrices
data_1 = data_1[::-1]
data_2 = data_2[::-1]
data_3 = data_3[::-1]
list_class = list_class[::-1]
#x_label = x_label[::-1]
y_label = y_label[::-1]

# Results
print(data_1)
print(data_2)
print(data_3)
print(data_4)

# GRAPH
# Create Subplots
fig = make_subplots(
    rows=2,
    cols=2,
    row_heights=[0.9, 0.1],
    column_widths=[0.9, 0.1],
    vertical_spacing=0.05,
    horizontal_spacing=0.05,
    print_grid=True,
    #start_cell='bottom-left',
    shared_xaxes=True,
    shared_yaxes=True,
    #specs=[[{'colspan': 2}, {'type': 'heatmap'}], [{'type': 'heatmap'}, None]],
    specs=[
        [{'rowspan': 1, 'colspan': 1}, {'rowspan': 1, 'colspan': 1}],
        [{'rowspan': 1, 'colspan': 1}, {'rowspan': 1, 'colspan': 1}],
    ],
    #insets=[{'cell': (1,1), 'l': 0.0, 'b': 1.0, 'w': 20.1}],
    #figure=
)

# Make Annotated Heatmap
fig1 = ff.create_annotated_heatmap(
    data_1,
    text=list_class,
    x=x_label,
    y=y_label,
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)
fig2 = ff.create_annotated_heatmap(
    data_2,
    text=[['Total de Municípios<br>"{}"'.format(i) for i in y_label]],
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)
fig3 = ff.create_annotated_heatmap(
    data_3,
    text=[['Total de Municípios<br>"{}"'.format(i) for i in x_label]],
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)
fig4 = ff.create_annotated_heatmap(
    data_4,
    text=[['Total de Municípios do Estado']],
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)

# Adds
fig.add_trace(fig1.data[0], 1, 1)
fig.add_trace(fig2.data[0], 1, 2)
fig.add_trace(fig3.data[0], 2, 1)
fig.add_trace(fig4.data[0], 2, 2)

# Label
annot1 = list(fig1.layout.annotations)
annot2 = list(fig2.layout.annotations)
annot3 = list(fig3.layout.annotations)
annot4 = list(fig4.layout.annotations)
for k in range(len(annot2)):
    annot2[k]['xref'] = 'x2'
    annot2[k]['yref'] = 'y2'
for k in range(len(annot3)):
    annot3[k]['xref'] = 'x3'
    annot3[k]['yref'] = 'y3'
for k in range(len(annot4)):
    annot4[k]['xref'] = 'x4'
    annot4[k]['yref'] = 'y4'
fig.update_layout(annotations=annot1+annot2+annot3+annot4)

# Updates
fig.update_layout(
    #title_text='URAEs <i>vs.</i> RMs/AUs',
    width=800,
    height=800,
    showlegend=False,
    #hovermode='closest',
    #autosize=True,
    xaxis=go.layout.XAxis(
        tickangle=-40,
        side='top'
    ),
)
fig.update_traces(
    #colorbar_tickangle=60,
    #selector=dict(type='heatmap')
)

# Results
fig.show()

My result always gives an x-axis misalignment and overlap with the subplot (1,2).

Could someone help me to fix this overlapping?

Hi @michelmetran,

I modified your code starting with fig=make_subplots():

  • The sum of row widths and horizontal_spacing must be 1 and similarly for columns;
  • I reduced the number of subplots settings;
  • splitted the y_labels in two substrings displayed on distinct lines;
  • manually set xaxis_domain because make_subplots() didn’t it, and the missing domain generated cell overlapping:
fig = make_subplots(
    rows=2,
    cols=2,
    row_heights=[0.80, 0.15],
    column_widths=[0.8, 0.15],
    vertical_spacing=0.05,
    horizontal_spacing=0.05,
    print_grid=True,
   
    shared_xaxes=True,
    shared_yaxes=True,
    
)
y_label=['_Fora de RMs/AUs',
 'Região Metropolitana<br> do V do Paraíba e Lit Norte',
 'Região Metropolitana<br> de São Paulo',
 'Região Metropolitana<br> de Sorocaba',
 'Região Metropolitan<br> de Ribeirão Preto',
 'Região Metropolitana<br> de Campinas',
 'Região Metropolitana<br> da Baixada Santista',
 'Aglomeração Urbana<br> de Piracicaba-AU- Piracicaba',
 'Aglomeração Urbana<br> de Jundiaí',
 'Aglomeração Urbana<br> de Franca']
# Make Annotated Heatmap
fig1 = ff.create_annotated_heatmap(
    z=data_1,
    text=list_class,
    x=x_label,
    y=y_label,
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)
fig2 = ff.create_annotated_heatmap(
    z=data_2,
    text=[['Total de Municípios<br>"{}"'.format(i) for i in y_label]],
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)
fig3 = ff.create_annotated_heatmap(
    z=data_3,
    text=[['Total de Municípios<br>"{}"'.format(i) for i in x_label]],
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)
fig4 = ff.create_annotated_heatmap(
    z=data_4,
    text=[['Total de Municípios do Estado']],
    colorscale='YlGnBu',
    #font_colors=['black'],
    hoverinfo='text',
)

# Adds
fig.add_trace(fig1.data[0], 1, 1)
fig.add_trace(fig2.data[0], 1, 2)
fig.add_trace(fig3.data[0], 2, 1)
fig.add_trace(fig4.data[0], 2, 2)

# Label
annot1 = list(fig1.layout.annotations)
annot2 = list(fig2.layout.annotations)
annot3 = list(fig3.layout.annotations)
annot4 = list(fig4.layout.annotations)
for k in range(len(annot2)):
    annot2[k]['xref'] = 'x2'
    annot2[k]['yref'] = 'y2'
for k in range(len(annot3)):
    annot3[k]['xref'] = 'x3'
    annot3[k]['yref'] = 'y3'
for k in range(len(annot4)):
    annot4[k]['xref'] = 'x4'
    annot4[k]['yref'] = 'y4'
fig.update_layout(annotations=annot1+annot2+annot3+annot4)

# Updates
fig.update_layout(
    #title_text='URAEs <i>vs.</i> RMs/AUs',
    width=700,
    height=700,
    showlegend=False,
    font_size=11,
    #hovermode='closest',
    #autosize=True,
    xaxis=go.layout.XAxis(
        tickangle=-40,
        side='top'
    ),
)
fig.update_traces(
    #colorbar_tickangle=60,
    #selector=dict(type='heatmap')
)
fig.update_layout(xaxis_domain=[0.0, 0.8])
fig.show()

1 Like

Oww!
A lot better!
I will study more about this “domain”.
Thanks a lot! :smiley:

@michelmetran

fig.data are mapped onto a normalized window, [0,1] x [0,1].
Each subplot has allocated a domain (rectangle) within this window, defined by the corresponding xaxis_domain and yaxis domain, which are subinterals in [0,1]

JUst print fig.layout to inspect subplot domains.