I\'d like to make a stacked bar chart where:
y axis : md litho
x axis : litho
The data:
I already tried to make it, using the code
A pcolormesh
is a mesh of rectangles, where individual heights can be assigned to rows (and columns). The first parameter of pcolormesh
are the mesh borders on the x-axis, the second for the y-axis. Such a mesh needs one row and one column more than there are values, so 2 in the x-direction and 7 in the y-direction for a 1x6
mesh.
The values need to be stored in a matrix (the third parameter). To create the matrix, the following steps are taken:
df['litho']
is the list of strings[:-1]
takes all elements except the last.map(d2)
maps the strings to numbers.to_numpy()
converts to pandas series to a numpy array.reshape(-1, 1)
converts the 1D array to a 2D array, where the number of rows is equal to the length of the 1D array (-1
means: the number needed to make the 1D and 2D array have the same number of elements) and the number of columns is 1Note that vmin
and vmax
need to be set explicitly because not all possible values are present in the matrix.
For the figure size, it's easier to use the object-oriented interface, using fig
and ax
instead of plt.
. fig, ax = plt.subplots(...)
allows to set the size, and can also create multiple subplots.
Apart from the figure size, also the aspect ratio of 'ax' (the inner plot) can be set. In the example below, an aspect ratio of 0.01
is used, which means the 442 units in the y-axis will occupy the same number of pixels as 100 times the 1 unit on the x-axis.
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from matplotlib.patches import Patch
import pandas as pd
df = pd.DataFrame({'md litho': [0, 31, 49, 67, 406, 427, 442],
'litho': ['NC', 'AT', 'BTT', 'NC', 'ABT', 'BAT', 'NC']})
d2 = {'ABT': 1, 'AT': 2, 'BAT': 3, 'BTT': 4, 'GT': 5, 'NC': 6, 'TT': 7}
colors = ['firebrick', 'red', 'peru', 'salmon', 'maroon', 'ghostwhite', 'pink']
cmap = ListedColormap(colors)
fig, ax = plt.subplots(figsize=(6, 4))
ax.pcolormesh([0, 1], df['md litho'], df['litho'][:-1].map(d2).to_numpy().reshape(-1, 1),
cmap=cmap, vmin=1, vmax=len(colors))
ax.set_xticks([]) # hide ticks on the x-axis
ax.set_yticks(df['md litho']) # optionally set the y-ticks to indicate the row borders
ax.set_aspect(0.01)
hands = [Patch(color=col, label=k) for k, col in zip(d2.keys(), colors)]
ax.legend(handles=hands, bbox_to_anchor=(1.03, 1.02), loc='upper left', fontsize=12, facecolor='lightgrey')
plt.tight_layout() # this fits the legend and the labels nicely into the figure
plt.show()
PS: Use ax.invert_yaxis()
to have zero at the top.