0

I have the following plot created with matplotlib

genres_list=['Action', 'Adventure', 'Animation', 'Children', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War', 'Western']

model_evaluation=np.array([0.        , 0.        , 0.        , 0.        , 0.8366437 ,
       0.        , 0.        , 0.73629546, 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.        ], dtype=np.float32)
fig=plt.figure()
ax=fig.add_subplot(111)
plt.rcParams["figure.figsize"] = (10,8)

plt.xticks(range(len(genres_list)), rotation=0, ha='center', fontsize=8)
plt.grid(b=True)
color_labels="black"

ax.bar(genres_list, model_evaluation)
ax.set(xlabel='Movie Genre', ylabel='F1 score', title='F1 score per movie genre', xticklabels=genres_list)
ax.spines['left'].set_color(color_labels)
ax.spines['bottom'].set_color(color_labels)
ax.tick_params(axis='x', colors=color_labels, which='major', pad=8)
ax.tick_params(axis='y', colors=color_labels)
ax.yaxis.label.set_color(color_labels)
ax.xaxis.label.set_color(color_labels)
ax.title.set_color(color_labels)

for i, f1 in enumerate(model_evaluation):
    ax.annotate(round(f1, 2), (i, f1), ha='center', va='bottom')

plt.show()

Output:

enter image description here

As you can see the long genres eat space from the shorter genre names like in the Documentary genre which falls upon Crime and Drame.

I want to leave equal space from each genre but based on the length of the longest name, which is the Documentary genre.

Based on the links below:

I made the following code adjustments:

ax.tick_params(axis='x', colors=color_labels, which='major', pad=8, labelsize=6.5)

Output after the adjustment:

enter image description here

After the adjustment the genre Documentary is not equally spaced between its left and right genre.

So my question is how can place all the genres equally from one another based on the length of the longest genre (Documentary).

NikSp
  • 1,262
  • 2
  • 19
  • 42
  • An alternative would be to rotate the tick labels by 90 degrees (which would also make them more readable) . Otherwise, try [pyplot.table](https://matplotlib.org/stable/gallery/misc/table_demo.html#sphx-glr-gallery-misc-table-demo-py) to adjust the spacing or [pyplot.subplots_adjust](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots_adjust.html#matplotlib.pyplot.subplots_adjust) to adjust the plot margins. – nish-ant Mar 01 '21 at 11:01
  • @nish-ant Indeed the plot rotation of xticks is an option, although I don't want to follow that path. I would like an approach that would keep the rotation on 0 degrees as in the code I posted ```rotation=0```. Now for the pyplot table can you post an example based on the code provided? It would really help me. – NikSp Mar 01 '21 at 11:06
  • 1
    In such cases, it is best to use `ax.barh()` to handle horizontal bar charts if you want to spend time adjusting the string. – r-beginners Mar 01 '21 at 12:02
  • @r-beginners I can acknowledge that as a valid proposal with a few adjustments in the script posted. – NikSp Mar 01 '21 at 12:15
  • Shall I post the revised horizontal bar graph as an answer? – r-beginners Mar 01 '21 at 12:45
  • @r-beginners let me post as an answer the code adjustments I made and a screenshot with the result based on your proposal (credits given). Then you may edit my solution/answer if you made up smth different or post a separate answer with a screenshot of the result so we can compare. – NikSp Mar 01 '21 at 13:14

1 Answers1

2

Based on the comment from @r-beginners I have changed the vertical barplot to a horizontal one (ax.hbar()). The code and the final output are posted below:

fig=plt.figure()
ax=fig.add_subplot(111)
plt.rcParams["figure.figsize"] = (10,10)

plt.yticks(range(len(genres_list)), rotation=0, ha='center', fontsize=10)
plt.grid(b=True)
color_labels="black"

ax.barh(genres_list, model_evaluation)
ax.set(ylabel='Movie Genre', xlabel='F1 score', title='F1 score per movie genre', yticklabels=genres_list)
ax.spines['left'].set_color(color_labels)
ax.spines['bottom'].set_color(color_labels)
ax.tick_params(axis='y', colors=color_labels, which='major', pad=30, labelsize=8)
ax.tick_params(axis='x', colors=color_labels)
ax.yaxis.label.set_color(color_labels)
ax.xaxis.label.set_color(color_labels)
ax.title.set_color(color_labels)

# credits of the for loop here: https://stackoverflow.com/a/42865017/10623444
for p in ax.patches:
    width = p.get_width()
    plt.text(0.03+p.get_width(), p.get_y()+0.55*p.get_height(), '{:1.2f}'.format(width), ha='center', va='center')

plt.show()

Output:

enter image description here

NikSp
  • 1,262
  • 2
  • 19
  • 42
  • 1
    It's more elegant than my code because it gets the value from ax.patches and sets it. There are a few things that bother me: the default color is black, and the graph size is not specified in plt.figure(figsize=(10,10)). Good luck! – r-beginners Mar 01 '21 at 13:28
  • @r-beginners Ty for the notes and out-of-box thinking. – NikSp Mar 01 '21 at 13:37