I have a barchart as displayed;
The code that produced this is as follows;
def create_bar_chart(_dict, _title, _title_text, titles, image_paths):
_fig = go.Figure()
df = pd.DataFrame(dict(score=_dict.values(), trait=_dict.keys()))
_image = f"{_title_text}_sm.jpg"
_width=600
_height=400
_fig = px.bar(df, x="trait", y="score")
_fig.update_layout(xaxis_title=None)
I want to put a horizontal line (with a width the same as the bar) for each bar which will indicate the average value. This value may be above the bar or within the bar. So for example with analytical thinking the average value may be 0.2 or 0.4, so I need a horizontal line with that score. How do I do this?
Below is my interpretation of the demand in the question, where a horizontal line of the same width as each bar is drawn at the height of some average score
import plotly.express as px
import pandas as pd
import numpy as np
data_dict = {
'trait': ['analytical thinking', 'cognitive processes', 'certainty', 'insight', 'abstract', 'concrete'],
'score': [0.35, 0.15, 0.02, 0.05, 0.42, 0.2]
}
X_COUNT = len(data_dict['trait'])
# The x-axis of bar chart is divided evenly by the number of x elements.
# This width is not necessarily the bar width, but the entire width for
# x element, which includes the bar and the two gaps on either side.
TOTAL_WIDTH = 1 / X_COUNT
# Set the gap between bars. It is a percentage of TOTAL_WIDTH. In other
# words, if we have TOTAL_WIDTH = 1 and BAR_GAP = 0.2, then the bar width
# would be 0.8 and the gaps between two bars would be 0.2
BAR_GAP = 0.2
fig = px.bar(pd.DataFrame.from_dict(data_dict), x='trait', y='score')
fig.update_layout(
width=600,
height=400,
bargap=BAR_GAP,
)
# The relative starting position of each bar (i.e., considering the width
# of the chart as 1)
bar_starts = np.cumsum([TOTAL_WIDTH] * X_COUNT) - 1 / X_COUNT
averages = [0.2, 0.3, 0.1, 0.02, 0.35, 0.25] # whatever average score to plot
for bs, ave in zip(bar_starts, averages):
line_st = bs + TOTAL_WIDTH * BAR_GAP / 2
fig.add_shape(
type='line',
x0=line_st,
y0=ave,
x1=line_st + TOTAL_WIDTH * (1 - BAR_GAP),
y1=ave,
xref='paper', # relative x position
yref='y' # exact y position as shown on the y-axis
)
fig.show()
The plot looks like this
This solution does not work if the plot needs to zoom in or out. The line size does not scale with the zoom.