Create vertical stacked bar chart referenced to y values (lithology/stratigraphic column)

前端 未结 1 1779
没有蜡笔的小新
没有蜡笔的小新 2021-01-27 00:46

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

相关标签:
1条回答
  • 2021-01-27 01:15

    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 1

    Note 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.

    0 讨论(0)
提交回复
热议问题