Hi All, I am trying to add 2 new axes to my plotly heatmap, "i_value’ to the xaxes and “l_freq” to the yaxes. I have ad a search around the web and looked at this example but I can’t work it out. Figure Factory Subplots | Python | Plotly
Can someone show me where I’m going wrong? I thought it would just be an update to layout but that doesn’t seem to work.
I have the basic heatmap working fine and outputting what I want initially.
Now I want to up the ante with a second plot but I need to be able to define the axes first.
Here is my code for preping and displaying the heatmap. its a bit lengthy butyh hopefully the comments are help[full
def do_heatmaps():
# Define our groups of business units
# all_teams - All business Units
# first_line - Firstline teams
# second_line - All secondline teams (Control Functions)
# all_it - All teams demmed to be IT
all_it = ['BCM', 'Business Inteligence' ,'IT Development' ,'IT Production' ,'Stockbroking Web Development', 'Information Security']
first_line = ['Client Services', 'Client Services APAC', 'Institutional Sales & Partners', 'Stockbroking Partners', 'Sales Trading', 'Trading incl. Pricing and Risk Dev', 'Marketing', 'Business Operations', 'Stockbroking Dealing & Business Operations', 'Market Data', 'Stockbroking Operations', 'Stockbroking Operations - APAC', 'Client Money', 'Stockbroking Client Money', 'Facilities', 'Business Change', 'GmbH', 'HR', 'Company Secretariat', 'Company Secretariat - APAC', 'Tax']
second_line = ['Finance', 'Legal', 'Data Privacy', 'Operational Risk', 'Financial Risk', 'Liquidity Risk', 'Compliance', 'Financial Crime']
all_teams = [all_it, first_line, second_line]
# Create our temp dataframe df and pull in the data we are interested in.
# We also use this oppertunity to remove blank entries
temp_df = raca_df[['risk_id', 'gross_impact','gross_likelihood', 'business_unit', 'net_impact', 'net_likelihood']].dropna()
# Get user to enter what functions they want reporting on. All, II, First Line, or Second line
def get_departments():
# Our prompt
prompt = 'Enter either All, IT, First, or Second to create matrix for these to create the relevant heatmap: '
while True:
try:
dept = input(prompt)
except ValueError:
print("Sorry, Only enter All, IT, First, or Second.")
continue
while dept not in ['All', 'IT', 'First', 'Second']:
print('Sorry, Invalid Input. Please try again')
dept = input('Enter either All, IT, First, or Second to create '
'matrix for these to create the relevant heatmap: ')
continue
else:
break
# Return user choice to our do_heatmaps() function
return dept
# Call get_departments() function and assign output to variable dept
dept = get_departments()
# Get our data ready for the heatmap
def heatmap_prep(data):
## Likelihood Assesment Weightings
## We have taken the midpoint in each of the ranges
# Highly Possible - Likely to crystalise more than once a year > 80%
la_hp = float(0.90)
# Possible - Likely to crystalise between once every two and a half years and once a year 40% to 80%
la_p = float(0.60)
# Unlikely - Likely to crystalise between once every five years and up to once every two and a half years 20% to 40%
la_u = float(0.30)
# Remote - Likely to crystalise between once every ten years and up to once every five years 10% to 20%
la_r = float(0.10)
# Very Remote - Likely to crystalise less than once every ten years < 10%
la_vr = float(0.05)
## Frequency Assesment weightings
## We have taken the midpoint in each of the ranges
# Highly Possible - 50% chance of happening in the next 12 months or occurs at least once every 2 years
fa_hp = float(0.50)
# Possible - 20% – 50% chance of happening in the next 12 months or occurs once in every 2 to 5 years
fa_p = float(0.35)
# Unlikely - 10% - 20% chance of happening in the next 12 months or occurs once in every 5 to 10 years
fa_u = float(0.15)
# Remote - ≤10% chance of happening in the next 12 months or occurs less than once in every 10 to 20 years
fa_r = float(0.05)
# Very Remote - ≤5% chance of happening in the next 12 months or occurs less than once in every 20 to 100 years
fa_vr = float(0.025)
# Extremly Remote - ≤1% chance of happening in the next 12 months or occurs no more than once in every 100 to 200
# years or less
fa_er = float(0.005)
# Set our heatmap dataframe dependant on value of dept
if dept == 'IT':
hm_df = temp_df[temp_df["business_unit"].isin([val for val in all_it])]
elif dept == 'First':
hm_df = temp_df[temp_df["business_unit"].isin([val for val in first_line])]
elif dept == 'Second':
hm_df = temp_df[temp_df["business_unit"].isin([val for val in second_line])]
elif dept == 'All':
hm_df = temp_df[temp_df["business_unit"].isin([val for sublist in all_teams for val in sublist])]
else:
print('Now how the fudge did we get here!!!!!!!')
# loop through our columns and set the type accordingly.
# Here we set it to int to prevent us getting the following error
# "IndexError: arrays used as indices must be of integer (or boolean) type"
for item in ['gross_impact','gross_likelihood','net_impact', 'net_likelihood']:
hm_df[item] = hm_df[item].astype('int')
# get our counts of the gross number of impact,likelihood pair
grosscount = hm_df.groupby(['gross_impact','gross_likelihood']).apply(len).reset_index().values
# # get our counts of the number of impact,likelihood pair
netcount = hm_df.groupby(['net_impact','net_likelihood']).apply(len).reset_index().values
# # Set up a blank 5 x 5 array and fill with zeros - Gross
heatmap_gr = np.zeros((np.max(5), np.max(5)),dtype=int)
# # Set up a blank 5 x 5 array and fill with zeros - Net
heatmap_nr = np.zeros((np.max(5), np.max(5)),dtype=int)
# # Set up a blank 5 x 5 array and fill with zeros - Weighted Inherent
weighted_gr = np.zeros((np.max(5), np.max(5)), dtype=float)
# # Set up a blank 5 x 5 array and fill with zeros - Weighted Residual
weighted_nr = np.zeros((np.max(5), np.max(5)), dtype=float)
# # Map the counts to our matrix
# # the -1 makes python count from 1 not 0.
heatmap_gr[grosscount[:,1]-1, grosscount[:,0]-1] = grosscount[:,2]
heatmap_nr[netcount[:,1]-1, netcount[:,0]-1] = netcount[:,2]
# Create copies of our gross and net risk arrays so we can apply a likelihood weighting.
# Setup our weighted risk arrays for Inherent (Gross) and Residual (net) risk
#Inherent
weighted_gr[0] = heatmap_gr[0] * la_vr
weighted_gr[1] = heatmap_gr[1] * la_r
weighted_gr[2] = heatmap_gr[2] * la_u
weighted_gr[3] = heatmap_gr[3] * la_p
weighted_gr[4] = heatmap_gr[4] * la_hp
# Set to 2 decimal places
np.round(weighted_gr,decimals = 2)
#Residual
weighted_nr[0] = heatmap_nr[0] * la_vr
weighted_nr[1] = heatmap_nr[1] * la_r
weighted_nr[2] = heatmap_nr[2] * la_u
weighted_nr[3] = heatmap_nr[3] * la_p
weighted_nr[4] = heatmap_nr[4] * la_hp
# Set to 2 decimal places
np.round(weighted_nr,decimals = 2)
# X axes labels
impact=['Minor', 'Important', 'Significant', 'Major', 'Critical']
i_value = ['> £5m',
'< £5m',
'< £2m',
'< £250k',
'< 50k'
]
# Y axes labels
likelihood=['Very Remote', 'Remote', 'Unlikely', 'Possible', 'Highly Possible']
l_freq = ['50% chance of happening in the next 12 months or occurs at least once every 2 years',
'20% – 50% chance of happening in the next 12 months or occurs once in every 2 to 5 years',
'10% - 20% chance of happening in the next 12 months or occurs once in every 5 to 10 years',
'≤10% chance of happening in the next 12 months or occurs less than once in every 10 to 20 years',
'≤5% chance of happening in the next 12 months or occurs less than once in every 20 to 100 years'
]
# Only show rounded value
gr_text = np.round(heatmap_gr, decimals=2)
nr_text = np.round(heatmap_nr, decimals=2)
wgr_text = np.round(weighted_gr, decimals=2)
wnr_text = np.round(weighted_nr, decimals=2)
# Setup our hovertext for gross risk
# This piece of code remaps x, y, and z to whatever we specify inour hovertext_gr line in the second for loop
hovertext_gr = list()
for yi, yy in enumerate(likelihood):
hovertext_gr.append(list())
for xi, xx in enumerate(impact):
hovertext_gr[-1].append('Impact: {}<br />Likelihood: {}<br />Number of Risks: {}'.format(xx,yy,heatmap_gr[yi][xi]))
# Setup our hovertext for net risk
# This piece of code remaps x, y, and z to whatever we specify inour hovertext_nr line in the second for loop
hovertext_nr = list()
for yj, yz in enumerate(likelihood):
hovertext_nr.append(list())
for xj, xz in enumerate(impact):
hovertext_nr[-1].append('Impact: {}<br />Likelihood: {}<br />Number of Risks: {}'.format(xz,yz,heatmap_nr[yj][xj]))
return heatmap_gr, heatmap_nr, impact, likelihood, gr_text, nr_text, wgr_text, wnr_text, hovertext_gr, hovertext_nr, weighted_gr, weighted_nr, i_value, l_freq
# Unpack our return values from heatmap_prep function
heatmap_gr, heatmap_nr, impact, likelihood, gr_text, nr_text, wgr_text, wnr_text, hovertext_gr, hovertext_nr, weighted_gr, weighted_nr, i_value, l_freq = heatmap_prep(dept)
def display_heatmap(heatmap_gr, heatmap_nr, impact, likelihood, gr_text, nr_text, wgr_text, wnr_text, hovertext_gr, hovertext_nr, weighted_gr, weighted_nr, i_value, l_freq):
fig_gr = ff.create_annotated_heatmap(heatmap_gr,
x=impact,
y=likelihood,
colorscale='Blues',
hoverinfo ='text',
text = hovertext_gr
)
fig_nr = ff.create_annotated_heatmap(heatmap_nr,
x=impact,
y=likelihood,
colorscale='Blues',
hoverinfo ='text',
text = hovertext_nr
)
weight_gr = ff.create_annotated_heatmap(weighted_gr,
x=impact,
y=likelihood,
colorscale='Reds',
hoverinfo ='text',
text = hovertext_gr
)
weight_nr = ff.create_annotated_heatmap(weighted_nr,
x=impact,
y=likelihood,
colorscale='Reds',
hoverinfo ='text',
text = hovertext_nr
)
# Setup the Heatmap layout for our Heatmaps
if dept == 'IT':
fig_gr.layout.update({'title': "Gross Risk Distribution - All IT (Count)"}, title_x=0.5)
fig_nr.layout.update({'title': "Net Risk Distribution - All IT (Count)"}, title_x=0.5)
weight_gr.layout.update({'title': "Inherent Risk - All IT (Weighted)"}, title_x=0.5)
weight_nr.layout.update({'title': "Residual Risk - All IT (Weighted)"}, title_x=0.5)
# # initialize xaxis2 and yaxis2
# fig_gr['layout']['xaxis2'] = {}
# fig_gr['layout']['yaxis2'] = {}
# # Edit layout for subplots
# fig_gr.layout.yaxis.update({'domain': [0, .5]})
# fig_gr.layout.yaxis2.update({'domain': [.6, 1]})
# # The graph's yaxis2 MUST BE anchored to the graph's xaxis2 and vice versa
# fig_gr.layout.yaxis2.update({'anchor': 'x2'})
# fig_gr.layout.xaxis2.update({'anchor': 'y2'})
# fig_gr.layout.yaxis2.update({'title': l_freq[0]}, title=0.5)
elif dept == 'First':
fig_gr.layout.update({'title': "Gross Risk Distribution - First Line Functions (Count)"}, title_x=0.5)
fig_nr.layout.update({'title': "Net Risk Distribution - First Line Functions (Count)"}, title_x=0.5)
weight_gr.layout.update({'title': "Inherent Risk - First Line (Weighted)"}, title_x=0.5)
weight_nr.layout.update({'title': "Residual Risk - First Line (Weighted)"}, title_x=0.5)
elif dept == 'Second':
fig_gr.layout.update({'title': "Gross Risk Distribution - Second Line Functions (Count)"}, title_x=0.5)
fig_nr.layout.update({'title': "Net Risk Distribution - Second Line Functions (Count)"}, title_x=0.5)
weight_gr.layout.update({'title': "Inherent Risk - Second Line (Weighted)"}, title_x=0.5)
weight_nr.layout.update({'title': "Residual Risk - Second Line (Weighted)"}, title_x=0.5)
elif dept == 'All':
fig_gr.layout.update({'title': "Gross Risk Distribution - All Business Functions (Count)"}, title_x=0.5)
fig_nr.layout.update({'title': "Net Risk Distribution - All Business Functions (Count)"}, title_x=0.5)
weight_gr.layout.update({'title': "Inherent Risk - All Business Functions (Weighted)"}, title_x=0.5)
weight_nr.layout.update({'title': "Residual Risk - All Business Functions (Weighted)"}, title_x=0.5)
else:
print('Now how the fudge did we get here!!!!!!!')
fig_gr.show()
weight_gr.show()
fig_nr.show()
weight_nr.show()
display_heatmap(heatmap_gr, heatmap_nr, impact, likelihood,
gr_text, nr_text, wgr_text, wnr_text,
hovertext_gr, hovertext_nr, weighted_gr, weighted_nr,
i_value, l_freq
)