nschloe / matplotx

:bar_chart: More styles and useful extensions for Matplotlib

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for horizontal barchart

RemDelaporteMathurin opened this issue · comments

matplotx.show_bar_values works perfectly with vertical bar charts but not with horizontal bar charts.

These are often used with long text labels.

import matplotlib.pyplot as plt
import matplotx

labels = ["Australia", "Brazil", "China", "Germany", "Mexico", "United\nStates"]
vals = [21.65, 24.5, 6.95, 8.40, 21.00, 8.55]
ypos = range(len(vals))

with plt.style.context(matplotx.styles.dufte_bar):
    plt.barh(ypos, vals)
    plt.yticks(ypos, labels)
    matplotx.show_bar_values("{:.2f}")
    plt.title("average temperature [°C]")
    plt.tight_layout()
    plt.show()

Produces:
image

I can write a PR and add a show_hbar_values() function that works with horizontal bar charts and produces:
image

Or it can also be an argument of matplotx.show_bar_value defaulting to "vertical" like show_bar_value(alignement="horizontal")

What do you think @nschloe ?

@nschloe the following produces the plot shown above. I can make a PR.

import matplotlib.pyplot as plt
import matplotx

labels = ["Australia", "Brazil", "China", "Germany", "Mexico", "United\nStates"]
vals = [21.65, 24.5, 6.95, 8.40, 21.00, 8.55]
ypos = range(len(vals))


def show_hbar_values(fmt: str = "{}") -> None:
    ax = plt.gca()

    # turn off x-ticks and x-grid
    plt.tick_params(axis="x", which="both", bottom=False, top=False, labelbottom=False)
    plt.grid(False)

    # remove margins
    plt.margins(y=0)

    data_to_axis = ax.transData + ax.transAxes.inverted()
    axis_to_data = ax.transAxes + ax.transData.inverted()

    for rect in ax.patches:
        # height = rect.get_height()
        width = rect.get_width()
        xpos_ax = data_to_axis.transform([1.0, width])
        xpos = axis_to_data.transform(xpos_ax - 0.3)[1]
        ax.text(
            xpos,
            rect.get_y() + rect.get_height() / 2 - 0.1,
            fmt.format(width),
            size=14,
            weight="bold",
            ha="center",
            va="bottom",
            color="white",
        )


with plt.style.context(matplotx.styles.dufte_bar):
    plt.barh(ypos, vals)
    plt.yticks(ypos, labels)
    show_hbar_values("{:.2f}")
    plt.title("average temperature [°C]")
    plt.tight_layout()
    plt.show()

Yeah sure, why not.