I'm working on a quadrant chart, but a bit stumped on how to get some annotations outside of my Plotly
quadrant chart. I have provided some data data and code that I used below.
#the libraries
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
import seaborn as sns
Sample of the data that I used:
#the data
data = pd.DataFrame({
'label': ['bf', 'lv', 'emp', 'ovg', 'cfr', 'osc', 'osh', 'osc', 'ost', 'osp'],
'score': [0.407, 0.392, 0.562, 0.456, 0.350, 0.410, 0.362, 0.373, 0.313, 0.342],
'wgt': [26.43, 16.80, 16.08, 15.86, 6.83, 5.31, 4.77, 2.99, 2.80, 2.13]
})
print(data)
Finally, the code that I used in generating the quadrant chart is below. Some of it borrowed from this Medium article.
fig = px.scatter(data, x=data.score, y=data.wgt, text=data.label,
title='main_title',
width=800, height=600)
# calculate averages
x_avg = data['score'].mean()
y_avg = data['wgt'].mean()
# add horizontal and vertical lines
fig.add_vline(x=x_avg, line_width=1, opacity=0.2)
fig.add_hline(y=y_avg, line_width=1, opacity=0.2)
# set x limits
adj_x = max((data['score'].max() - x_avg), (x_avg - data['score'].min())) * 1.1
lb_x, ub_x = (x_avg - adj_x, x_avg + adj_x)
fig.update_xaxes(range = [lb_x, ub_x])
# set y limits
adj_y = max((data['wgt'].max() - y_avg), (y_avg - data['wgt'].min())) * 1.1
lb_y, ub_y = (y_avg - adj_y, y_avg + adj_y)
fig.update_yaxes(range = [lb_y, ub_y])
# update x tick labels
axis = ['Low', 'High']
fig.update_layout(
xaxis_title='xtitle',
xaxis = dict(
tickmode = 'array',
tickvals = ([(x_avg - adj_x / 2), (x_avg + adj_x / 2)]),
ticktext = axis
)
)
# update y tick labels
fig.update_layout(
yaxis_title='ytitle',
yaxis = dict(
tickmode = 'array',
tickvals = ([(y_avg - adj_y / 2), (y_avg + adj_y / 2)]),
ticktext = axis,
tickangle=270
)
)
fig.update_layout(margin=dict(t=50, l=5, r=5, b=50),
title={'text': 'pl',
'font_size': 20,
'y':1.0,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top'})
# where I need the help with annotation
fig.add_annotation(x=data['score'].min(), y=data['wgt'].min(),
text="Quad 3",
yref='paper',
showarrow=False)
fig.add_annotation(x=data['score'].max(), y=data['wgt'].min(),
text="Quad 4",
yref='paper',
showarrow=False)
fig.add_annotation(x=data['score'].min(), y=data['wgt'].max(),
text="Quad 1",
yref='paper',
showarrow=False)
fig.add_annotation(x=data['score'].max(), y=data['wgt'].max(),
text="Quad 2",
yref='paper',
showarrow=False)
fig.show()
The final output I am looking for should look like the chart below. So, specifically, what I need some assistance with is how to position the texts Quad 1 through 4 outside as shown below :
You need to add margins and then set the coordinates accordingly for each position. here is a code I used with absolute coordinates.
fig = px.scatter(data, x=data.score, y=data.wgt, text=data.label,
title='main_title',
width=800, height=600)
# calculate averages
x_avg = data['score'].mean()
y_avg = data['wgt'].mean()
# add horizontal and vertical lines
fig.add_vline(x=x_avg, line_width=1, opacity=0.2)
fig.add_hline(y=y_avg, line_width=1, opacity=0.2)
# set x limits
adj_x = max((data['score'].max() - x_avg), (x_avg - data['score'].min())) * 1.1
lb_x, ub_x = (x_avg - adj_x, x_avg + adj_x)
fig.update_xaxes(range = [lb_x, ub_x])
# set y limits
adj_y = max((data['wgt'].max() - y_avg), (y_avg - data['wgt'].min())) * 1.1
lb_y, ub_y = (y_avg - adj_y, y_avg + adj_y)
fig.update_yaxes(range = [lb_y, ub_y])
# update x tick labels
axis = ['Low', 'High']
fig.update_layout(
xaxis_title='xtitle',
xaxis = dict(
tickmode = 'array',
tickvals = ([(x_avg - adj_x / 2), (x_avg + adj_x / 2)]),
ticktext = axis
)
)
# update y tick labels
fig.update_layout(
yaxis_title='ytitle',
yaxis = dict(
tickmode = 'array',
tickvals = ([(y_avg - adj_y / 2), (y_avg + adj_y / 2)]),
ticktext = axis,
tickangle=270
)
)
fig.update_layout(margin=dict(t=50, l=5, r=5, b=50),
title={'text': 'pl',
'font_size': 20,
'y':1.0,
'x':0.5,
'xanchor': 'center',
'yanchor': 'top'})
# where I need the help with annotation
fig.add_annotation(dict(font=dict(color="black",size=18),
x=0, y=-0.15,#data['score'].min()-0.2, y=data['wgt'].min()-0.2,
text="Quad 3",
xref='paper',
yref='paper',
showarrow=False))
fig.add_annotation(dict(font=dict(color="black",size=18),
x=1, y=-0.15,#x=data['score'].max(), y=data['wgt'].min(),
text="Quad 4",
xref='paper',
yref='paper',
showarrow=False))
fig.add_annotation(dict(font=dict(color="black",size=18),
x=0, y=1.15, #x=data['score'].min(), y=data['wgt'].max(),
text="Quad 1",
xref='paper',
yref='paper',
showarrow=False))
fig.add_annotation(dict(font=dict(color="black",size=18),
x=1, y=1.15, #x=data['score'].max(), y=data['wgt'].max(),
text="Quad 2",
xref='paper',
yref='paper',
showarrow=False))
fig.update_layout(
margin=dict(l=20, r=20, t=100, b=100),
)
fig.show()