mgplot.bar_plot

bar_plot.py This module contains functions to create bar plots using Matplotlib. Note: bar plots in Matplotlib are not the same as bar charts in other libraries. Bar plots are used to represent categorical data with rectangular bars. As a result, bar plots and line plots typically cannot be plotted on the same axes.

  1"""
  2bar_plot.py
  3This module contains functions to create bar plots using Matplotlib.
  4Note: bar plots in Matplotlib are not the same as bar charts in other
  5libraries. Bar plots are used to represent categorical data with
  6rectangular bars. As a result, bar plots and line plots typically
  7cannot be plotted on the same axes.
  8"""
  9
 10# --- imports
 11from typing import Any, Final
 12from collections.abc import Sequence
 13from pandas import DataFrame, period_range, PeriodIndex
 14import matplotlib.pyplot as plt
 15from matplotlib.pyplot import Axes
 16
 17from mgplot.settings import DataT, get_setting
 18from mgplot.utilities import apply_defaults, get_color_list, get_axes, constrain_data
 19from mgplot.kw_type_checking import (
 20    ExpectedTypeDict,
 21    validate_expected,
 22    report_kwargs,
 23    validate_kwargs,
 24)
 25from mgplot.date_utils import set_labels
 26
 27
 28# --- constants
 29BAR_KW_TYPES: Final[ExpectedTypeDict] = {
 30    "color": (str, Sequence, (str,)),
 31    "width": float,
 32    "stacked": bool,
 33    "rotation": (int, float),
 34    "bar_legend": bool,
 35    "max_ticks": int,
 36    "plot_from": (int, PeriodIndex, type(None)),
 37}
 38validate_expected(BAR_KW_TYPES, "bar_plot")
 39
 40
 41# --- functions
 42def bar_plot(
 43    data: DataT,
 44    **kwargs,
 45) -> Axes:
 46    """
 47    Create a bar plot from the given data. Each column in the DataFrame
 48    will be stacked on top of each other, with positive values above
 49    zero and negative values below zero.
 50
 51    Parameters
 52    - data: Series - The data to plot. Can be a DataFrame or a Series.
 53    - **kwargs: dict Additional keyword arguments for customization.
 54        - color: list - A list of colors for the each series (column) in  the DataFrame.
 55        - width: float - The width of the bars.
 56        - stacked: bool - If True, the bars will be stacked.
 57        - rotation: int - The rotation angle in degrees for the x-axis labels.
 58        - bar_legend: bool - If True, show the legend. Defaults to True
 59          if more than one bar being plotted for each category.
 60        - "max_ticks": int - The maximum number of ticks on the x-axis,
 61          (this option only applies to PeriodIndex data.).
 62
 63    Note: This function does not assume all data is timeseries with a PeriodIndex,
 64
 65    Returns
 66    - axes: Axes - The axes for the plot.
 67    """
 68
 69    # --- check the kwargs
 70    me = "bar_plot"
 71    report_kwargs(called_from=me, **kwargs)
 72    validate_kwargs(BAR_KW_TYPES, me, **kwargs)
 73
 74    # --- get the data
 75    # no call to check_clean_timeseries here, as bar plots are not
 76    # necessarily timeseries data. If the data is a Series, it will be
 77    # converted to a DataFrame with a single column.
 78    df = DataFrame(data)  # really we are only plotting DataFrames
 79    df, kwargs = constrain_data(df, **kwargs)
 80    item_count = len(df.columns)
 81
 82    defaults: dict[str, Any] = {
 83        "color": get_color_list(item_count),
 84        "width": get_setting("bar_width"),
 85        "stacked": False,
 86        "rotation": 90,
 87        "bar_legend": (item_count > 1),
 88        "max_ticks": 10,
 89    }
 90    bar_args, remaining_kwargs = apply_defaults(item_count, defaults, kwargs)
 91
 92    # --- plot the data
 93    axes, _rkwargs = get_axes(**remaining_kwargs)
 94
 95    df.plot.bar(
 96        ax=axes,
 97        color=bar_args["color"],
 98        stacked=bar_args["stacked"][0],
 99        width=bar_args["width"][0],
100        legend=bar_args["bar_legend"][0],
101    )
102
103    rotate_labels = True
104    if isinstance(df.index, PeriodIndex):
105        complete = period_range(
106            start=df.index.min(), end=df.index.max(), freq=df.index.freqstr
107        )
108        if complete.equals(df.index):
109            # if the index is complete, we can set the labels
110            set_labels(axes, df.index, bar_args["max_ticks"][0])
111            rotate_labels = False
112
113    if rotate_labels:
114        plt.xticks(rotation=bar_args["rotation"][0])
115
116    return axes
BAR_KW_TYPES: Final[ExpectedTypeDict] = {'color': (<class 'str'>, <class 'collections.abc.Sequence'>, (<class 'str'>,)), 'width': <class 'float'>, 'stacked': <class 'bool'>, 'rotation': (<class 'int'>, <class 'float'>), 'bar_legend': <class 'bool'>, 'max_ticks': <class 'int'>, 'plot_from': (<class 'int'>, <class 'pandas.core.indexes.period.PeriodIndex'>, <class 'NoneType'>)}
def bar_plot(data: ~DataT, **kwargs) -> matplotlib.axes._axes.Axes:
 43def bar_plot(
 44    data: DataT,
 45    **kwargs,
 46) -> Axes:
 47    """
 48    Create a bar plot from the given data. Each column in the DataFrame
 49    will be stacked on top of each other, with positive values above
 50    zero and negative values below zero.
 51
 52    Parameters
 53    - data: Series - The data to plot. Can be a DataFrame or a Series.
 54    - **kwargs: dict Additional keyword arguments for customization.
 55        - color: list - A list of colors for the each series (column) in  the DataFrame.
 56        - width: float - The width of the bars.
 57        - stacked: bool - If True, the bars will be stacked.
 58        - rotation: int - The rotation angle in degrees for the x-axis labels.
 59        - bar_legend: bool - If True, show the legend. Defaults to True
 60          if more than one bar being plotted for each category.
 61        - "max_ticks": int - The maximum number of ticks on the x-axis,
 62          (this option only applies to PeriodIndex data.).
 63
 64    Note: This function does not assume all data is timeseries with a PeriodIndex,
 65
 66    Returns
 67    - axes: Axes - The axes for the plot.
 68    """
 69
 70    # --- check the kwargs
 71    me = "bar_plot"
 72    report_kwargs(called_from=me, **kwargs)
 73    validate_kwargs(BAR_KW_TYPES, me, **kwargs)
 74
 75    # --- get the data
 76    # no call to check_clean_timeseries here, as bar plots are not
 77    # necessarily timeseries data. If the data is a Series, it will be
 78    # converted to a DataFrame with a single column.
 79    df = DataFrame(data)  # really we are only plotting DataFrames
 80    df, kwargs = constrain_data(df, **kwargs)
 81    item_count = len(df.columns)
 82
 83    defaults: dict[str, Any] = {
 84        "color": get_color_list(item_count),
 85        "width": get_setting("bar_width"),
 86        "stacked": False,
 87        "rotation": 90,
 88        "bar_legend": (item_count > 1),
 89        "max_ticks": 10,
 90    }
 91    bar_args, remaining_kwargs = apply_defaults(item_count, defaults, kwargs)
 92
 93    # --- plot the data
 94    axes, _rkwargs = get_axes(**remaining_kwargs)
 95
 96    df.plot.bar(
 97        ax=axes,
 98        color=bar_args["color"],
 99        stacked=bar_args["stacked"][0],
100        width=bar_args["width"][0],
101        legend=bar_args["bar_legend"][0],
102    )
103
104    rotate_labels = True
105    if isinstance(df.index, PeriodIndex):
106        complete = period_range(
107            start=df.index.min(), end=df.index.max(), freq=df.index.freqstr
108        )
109        if complete.equals(df.index):
110            # if the index is complete, we can set the labels
111            set_labels(axes, df.index, bar_args["max_ticks"][0])
112            rotate_labels = False
113
114    if rotate_labels:
115        plt.xticks(rotation=bar_args["rotation"][0])
116
117    return axes

Create a bar plot from the given data. Each column in the DataFrame will be stacked on top of each other, with positive values above zero and negative values below zero.

Parameters

  • data: Series - The data to plot. Can be a DataFrame or a Series.
  • **kwargs: dict Additional keyword arguments for customization.
    • color: list - A list of colors for the each series (column) in the DataFrame.
    • width: float - The width of the bars.
    • stacked: bool - If True, the bars will be stacked.
    • rotation: int - The rotation angle in degrees for the x-axis labels.
    • bar_legend: bool - If True, show the legend. Defaults to True if more than one bar being plotted for each category.
    • "max_ticks": int - The maximum number of ticks on the x-axis, (this option only applies to PeriodIndex data.).

Note: This function does not assume all data is timeseries with a PeriodIndex,

Returns

  • axes: Axes - The axes for the plot.