mgplot.growth_plot
growth_plot.py: plot period and annual/through-the-year growth rates on the same axes.
- calc_growth()
- growth_plot()
- series_growth_plot()
1""" 2growth_plot.py: 3plot period and annual/through-the-year growth rates on the same axes. 4- calc_growth() 5- growth_plot() 6- series_growth_plot() 7""" 8 9# --- imports 10from typing import Final 11 12from pandas import Series, DataFrame, Period, PeriodIndex, period_range 13from numpy import nan 14from matplotlib.pyplot import Axes 15from tabulate import tabulate 16 17from mgplot.bar_plot import bar_plot, BAR_KW_TYPES 18from mgplot.line_plot import line_plot, LINE_KW_TYPES 19from mgplot.axis_utils import map_periodindex 20from mgplot.test import prepare_for_test 21from mgplot.settings import DataT 22from mgplot.axis_utils import set_labels 23from mgplot.utilities import check_clean_timeseries, constrain_data 24from mgplot.kw_type_checking import ( 25 validate_kwargs, 26 report_kwargs, 27 validate_expected, 28 ExpectedTypeDict, 29 TransitionKwargs, 30 trans_check, 31 package_kwargs, 32) 33from mgplot.keyword_names import ( 34 # - common 35 AX, 36 REPORT_KWARGS, 37 LABEL_SERIES, 38 MAX_TICKS, 39 WIDTH, 40 COLOR, 41 STYLE, 42 ANNOTATE, 43 ANNOTATE_COLOR, 44 ROUNDING, 45 FONTSIZE, 46 FONTNAME, 47 ROTATION, 48 # - line related 49 LINE_WIDTH, 50 LINE_COLOR, 51 LINE_STYLE, 52 ANNOTATE_LINE, 53 LINE_ROUNDING, 54 LINE_FONTSIZE, 55 LINE_FONTNAME, 56 LINE_ANNO_COLOR, 57 # - bar related 58 ANNOTATE_BARS, 59 BAR_ROUNDING, 60 BAR_ROTATION, 61 BAR_WIDTH, 62 BAR_COLOR, 63 BAR_ANNO_COLOR, 64 BAR_FONTSIZE, 65 BAR_FONTNAME, 66 PLOT_FROM, 67 ABOVE, 68) 69 70# === constants 71 72# - overarching constants 73 74ANNUAL = "annual" 75PERIODIC = "periodic" 76 77GROWTH_KW_TYPES: Final[ExpectedTypeDict] = { 78 # --- common options 79 AX: (Axes, type(None)), 80 PLOT_FROM: (int, Period, type(None)), 81 LABEL_SERIES: (bool), 82 MAX_TICKS: int, 83 # --- options passed to the line plot 84 LINE_WIDTH: (float, int), 85 LINE_COLOR: str, 86 LINE_STYLE: str, 87 ANNOTATE_LINE: bool, # None, True 88 LINE_ROUNDING: (bool, int), # None, True or rounding 89 LINE_FONTSIZE: (str, int, float), # fontsize for the line annotations 90 LINE_FONTNAME: str, # font name for the line annotations 91 LINE_ANNO_COLOR: str, # color for the line annotations 92 # --- options passed to the bar plot 93 ANNOTATE_BARS: (type(None), bool), 94 BAR_FONTSIZE: (str, int, float), 95 BAR_FONTNAME: str, 96 BAR_ROUNDING: int, 97 BAR_WIDTH: float, 98 BAR_COLOR: str, 99 BAR_ANNO_COLOR: (str, type(None)), 100 BAR_ROTATION: (int, float), 101 ABOVE: bool, 102} 103validate_expected(GROWTH_KW_TYPES, "growth_plot") 104 105SERIES_GROWTH_KW_TYPES: Final[ExpectedTypeDict] = { 106 "ylabel": (str, type(None)), 107} | GROWTH_KW_TYPES 108validate_expected(SERIES_GROWTH_KW_TYPES, "growth_plot") 109 110 111# - transition of kwargs from growth_plot to line_plot 112common_transitions: TransitionKwargs = { 113 # arg-to-growth_plot : (arg-to-line_plot, default_value) 114 LABEL_SERIES: (LABEL_SERIES, True), 115 AX: (AX, None), 116 # MAX_TICKS: (MAX_TICKS, None), 117 PLOT_FROM: (PLOT_FROM, None), 118 REPORT_KWARGS: (REPORT_KWARGS, None), 119} 120trans_check(common_transitions, GROWTH_KW_TYPES, LINE_KW_TYPES, __name__) 121trans_check(common_transitions, GROWTH_KW_TYPES, BAR_KW_TYPES, __name__) 122 123to_line_plot: TransitionKwargs = common_transitions | { 124 # arg-to-growth_plot : (arg-to-line_plot, default_value) 125 LINE_WIDTH: (WIDTH, None), 126 LINE_COLOR: (COLOR, "darkblue"), 127 LINE_STYLE: (STYLE, None), 128 ANNOTATE_LINE: (ANNOTATE, True), 129 LINE_ROUNDING: (ROUNDING, None), 130 LINE_FONTSIZE: (FONTSIZE, None), 131 LINE_FONTNAME: (FONTNAME, None), 132 LINE_ANNO_COLOR: (ANNOTATE_COLOR, None), 133} 134trans_check(to_line_plot, GROWTH_KW_TYPES, LINE_KW_TYPES, __name__) 135 136# - constants for the bar plot 137to_bar_plot: TransitionKwargs = common_transitions | { 138 # arg-to-growth_plot : (arg-to-bar_plot, default_value) 139 BAR_WIDTH: (WIDTH, 0.8), 140 BAR_COLOR: (COLOR, "#dd0000"), 141 ANNOTATE_BARS: (ANNOTATE, True), 142 BAR_ROUNDING: (ROUNDING, None), 143 ABOVE: (ABOVE, False), 144 BAR_ROTATION: (ROTATION, None), 145 BAR_FONTSIZE: (FONTSIZE, None), 146 BAR_FONTNAME: (FONTNAME, None), 147 BAR_ANNO_COLOR: (ANNOTATE_COLOR, None), 148} 149trans_check(to_bar_plot, GROWTH_KW_TYPES, BAR_KW_TYPES, __name__) 150 151 152# === functions 153# --- public functions 154def calc_growth(series: Series) -> DataFrame: 155 """ 156 Calculate annual and periodic growth for a pandas Series, 157 where the index is a PeriodIndex. 158 159 Args: 160 - series: A pandas Series with an appropriate PeriodIndex. 161 162 Returns a two column DataFrame: 163 164 Raises 165 - TypeError if the series is not a pandas Series. 166 - TypeError if the series index is not a PeriodIndex. 167 - ValueError if the series is empty. 168 - ValueError if the series index does not have a frequency of Q, M, or D. 169 - ValueError if the series index has duplicates. 170 """ 171 172 # --- sanity checks 173 if not isinstance(series, Series): 174 raise TypeError("The series argument must be a pandas Series") 175 if not isinstance(series.index, PeriodIndex): 176 raise TypeError("The series index must be a pandas PeriodIndex") 177 if series.empty: 178 raise ValueError("The series argument must not be empty") 179 if series.index.freqstr[0] not in ("Q", "M", "D"): 180 raise ValueError("The series index must have a frequency of Q, M, or D") 181 if series.index.has_duplicates: 182 raise ValueError("The series index must not have duplicate values") 183 184 # --- ensure the index is complete and the date is sorted 185 complete = period_range(start=series.index.min(), end=series.index.max()) 186 series = series.reindex(complete, fill_value=nan) 187 series = series.sort_index(ascending=True) 188 189 # --- calculate annual and periodic growth 190 ppy = {"Q": 4, "M": 12, "D": 365}[PeriodIndex(series.index).freqstr[:1]] 191 annual = series.pct_change(periods=ppy) * 100 192 periodic = series.pct_change(periods=1) * 100 193 periodic_name = {4: "Quarterly", 12: "Monthly", 365: "Daily"}[ppy] + " Growth" 194 return DataFrame( 195 { 196 "Annual Growth": annual, 197 periodic_name: periodic, 198 } 199 ) 200 201 202def growth_plot( 203 data: DataT, 204 **kwargs, 205) -> Axes: 206 """ 207 Plot annual growth (as a line) and periodic growth (as bars) 208 on the same axes. 209 210 Args: 211 - data: A pandas DataFrame with two columns: 212 - kwargs: 213 # --- common options 214 ax: Axes | None -- the matplotlib Axes to plot on, or None to create a new one. 215 plot_from: Period | int | None -- the period to start plotting from 216 label_series: bool -- whether to label the series in the legend. 217 max_ticks: int -- maximum number of ticks on the x-axis 218 # --- options passed to the line plot 219 line_width: float | int -- the width of the line 220 line_color: str -- the color of the line 221 line_style: str -- the style of the line 222 annotate_line: None | bool -- whether to annotate the end of the line 223 line_rounding: bool | int -- rounding for line annotation 224 line_fontsize: str | int | float -- fontsize for the line annotation 225 line_fontname: str -- font name for the line annotation 226 line_anno_color: str | bool | None -- color for the line annotation 227 # --- options passed to the bar plot 228 bar_width: float, 229 bar_color: str, 230 annotate_bars: None | bool -- whether to annotate the bars 231 above: bool -- whether to place the bar annotations above the bars 232 bar_fontsize: str | int | float -- fontsize for the bar annotations 233 bar_fontname: str -- font name for the bar annotations 234 bar_rounding: bool | int -- rounding for bar annotation 235 bar_anno_color: str | None -- color for the bar annotation 236 bar_rotation: int | float -- rotation for the bar annotation 237 } 238 Returns: 239 - axes: The matplotlib Axes object. 240 241 Raises: 242 - TypeError if the annual and periodic arguments are not pandas Series. 243 - TypeError if the annual index is not a PeriodIndex. 244 - ValueError if the annual and periodic series do not have the same index. 245 """ 246 247 # --- check the kwargs 248 me = "growth_plot" 249 report_kwargs(called_from=me, **kwargs) 250 kwargs = validate_kwargs(GROWTH_KW_TYPES, me, **kwargs) 251 252 # --- data checks 253 data = check_clean_timeseries(data, me) 254 if len(data.columns) != 2: 255 raise TypeError("The data argument must be a pandas DataFrame with two columns") 256 data, kwargs = constrain_data(data, **kwargs) 257 258 # --- get the series of interest ... 259 annual = data[data.columns[0]] 260 periodic = data[data.columns[1]] 261 262 # --- series names 263 annual.name = "Annual Growth" 264 periodic.name = {"M": "Monthly", "Q": "Quarterly", "D": "Daily"}[ 265 PeriodIndex(periodic.index).freqstr[:1] 266 ] + " Growth" 267 268 # --- convert PeriodIndex periodic growth data to integer indexed data. 269 saved_pi = map_periodindex(periodic) 270 if saved_pi is not None: 271 periodic = saved_pi[0] # extract the reindexed DataFrame 272 273 # --- simple bar chart for the periodic growth 274 if BAR_ANNO_COLOR not in kwargs or kwargs[BAR_ANNO_COLOR] is None: 275 kwargs[BAR_ANNO_COLOR] = "black" if kwargs.get(ABOVE, False) else "white" 276 selected = package_kwargs(to_bar_plot, **kwargs) 277 axes = bar_plot(periodic, **selected) 278 279 # --- and now the annual growth as a line 280 selected = package_kwargs(to_line_plot, **kwargs) 281 line_plot(annual, ax=axes, **selected) 282 283 # --- fix the x-axis labels 284 if saved_pi is not None: 285 set_labels(axes, saved_pi[1], kwargs.get("max_ticks", 10)) 286 287 # --- and done ... 288 return axes 289 290 291def series_growth_plot( 292 data: DataT, 293 **kwargs, 294) -> Axes: 295 """ 296 Plot annual and periodic growth in percentage terms from 297 a pandas Series, and finalise the plot. 298 299 Args: 300 - data: A pandas Series with an appropriate PeriodIndex. 301 - kwargs: 302 - takes the same kwargs as for growth_plot() 303 """ 304 305 # --- check the kwargs 306 me = "series_growth_plot" 307 report_kwargs(called_from=me, **kwargs) 308 kwargs = validate_kwargs(SERIES_GROWTH_KW_TYPES, me, **kwargs) 309 310 # --- sanity checks 311 if not isinstance(data, Series): 312 raise TypeError( 313 "The data argument to series_growth_plot() must be a pandas Series" 314 ) 315 316 # --- calculate growth and plot - add ylabel 317 ylabel: str | None = kwargs.pop("ylabel", None) 318 if ylabel is not None: 319 print(f"Did you intend to specify a value for the 'ylabel' in {me}()?") 320 ylabel = "Growth (%)" if ylabel is None else ylabel 321 growth = calc_growth(data) 322 ax = growth_plot(growth, **kwargs) 323 ax.set_ylabel(ylabel) 324 return ax 325 326 327# --- test code 328if __name__ == "__main__": 329 print("Testing") 330 prepare_for_test("growth_plot") 331 series_ = Series([1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]) 332 series_.index = period_range("2020Q1", periods=len(series_), freq="Q") 333 growth_ = calc_growth(series_) 334 text_ = tabulate(growth_, headers="keys", tablefmt="pipe") # type: ignore[arg-type] 335 print(text_)
ANNUAL =
'annual'
PERIODIC =
'periodic'
GROWTH_KW_TYPES: Final[ExpectedTypeDict] =
{'ax': (<class 'matplotlib.axes._axes.Axes'>, <class 'NoneType'>), 'plot_from': (<class 'int'>, <class 'pandas._libs.tslibs.period.Period'>, <class 'NoneType'>), 'label_series': <class 'bool'>, 'max_ticks': <class 'int'>, 'line_width': (<class 'float'>, <class 'int'>), 'line_color': <class 'str'>, 'line_style': <class 'str'>, 'annotate_line': <class 'bool'>, 'line_rounding': (<class 'bool'>, <class 'int'>), 'line_fontsize': (<class 'str'>, <class 'int'>, <class 'float'>), 'line_fontname': <class 'str'>, 'line_annotate_color': <class 'str'>, 'annotate_bars': (<class 'NoneType'>, <class 'bool'>), 'bar_fontsize': (<class 'str'>, <class 'int'>, <class 'float'>), 'bar_fontname': <class 'str'>, 'bar_rounding': <class 'int'>, 'bar_width': <class 'float'>, 'bar_color': <class 'str'>, 'bar_annotate_color': (<class 'str'>, <class 'NoneType'>), 'bar_rotation': (<class 'int'>, <class 'float'>), 'above': <class 'bool'>}
SERIES_GROWTH_KW_TYPES: Final[ExpectedTypeDict] =
{'ylabel': (<class 'str'>, <class 'NoneType'>), 'ax': (<class 'matplotlib.axes._axes.Axes'>, <class 'NoneType'>), 'plot_from': (<class 'int'>, <class 'pandas._libs.tslibs.period.Period'>, <class 'NoneType'>), 'label_series': <class 'bool'>, 'max_ticks': <class 'int'>, 'line_width': (<class 'float'>, <class 'int'>), 'line_color': <class 'str'>, 'line_style': <class 'str'>, 'annotate_line': <class 'bool'>, 'line_rounding': (<class 'bool'>, <class 'int'>), 'line_fontsize': (<class 'str'>, <class 'int'>, <class 'float'>), 'line_fontname': <class 'str'>, 'line_annotate_color': <class 'str'>, 'annotate_bars': (<class 'NoneType'>, <class 'bool'>), 'bar_fontsize': (<class 'str'>, <class 'int'>, <class 'float'>), 'bar_fontname': <class 'str'>, 'bar_rounding': <class 'int'>, 'bar_width': <class 'float'>, 'bar_color': <class 'str'>, 'bar_annotate_color': (<class 'str'>, <class 'NoneType'>), 'bar_rotation': (<class 'int'>, <class 'float'>), 'above': <class 'bool'>}
common_transitions: mgplot.kw_type_checking.TransitionKwargs =
{'label_series': ('label_series', True), 'ax': ('ax', None), 'plot_from': ('plot_from', None), 'report_kwargs': ('report_kwargs', None)}
to_line_plot: mgplot.kw_type_checking.TransitionKwargs =
{'label_series': ('label_series', True), 'ax': ('ax', None), 'plot_from': ('plot_from', None), 'report_kwargs': ('report_kwargs', None), 'line_width': ('width', None), 'line_color': ('color', 'darkblue'), 'line_style': ('style', None), 'annotate_line': ('annotate', True), 'line_rounding': ('rounding', None), 'line_fontsize': ('fontsize', None), 'line_fontname': ('fontname', None), 'line_annotate_color': ('annotate_color', None)}
to_bar_plot: mgplot.kw_type_checking.TransitionKwargs =
{'label_series': ('label_series', True), 'ax': ('ax', None), 'plot_from': ('plot_from', None), 'report_kwargs': ('report_kwargs', None), 'bar_width': ('width', 0.8), 'bar_color': ('color', '#dd0000'), 'annotate_bars': ('annotate', True), 'bar_rounding': ('rounding', None), 'above': ('above', False), 'bar_rotation': ('rotation', None), 'bar_fontsize': ('fontsize', None), 'bar_fontname': ('fontname', None), 'bar_annotate_color': ('annotate_color', None)}
def
calc_growth(series: pandas.core.series.Series) -> pandas.core.frame.DataFrame:
155def calc_growth(series: Series) -> DataFrame: 156 """ 157 Calculate annual and periodic growth for a pandas Series, 158 where the index is a PeriodIndex. 159 160 Args: 161 - series: A pandas Series with an appropriate PeriodIndex. 162 163 Returns a two column DataFrame: 164 165 Raises 166 - TypeError if the series is not a pandas Series. 167 - TypeError if the series index is not a PeriodIndex. 168 - ValueError if the series is empty. 169 - ValueError if the series index does not have a frequency of Q, M, or D. 170 - ValueError if the series index has duplicates. 171 """ 172 173 # --- sanity checks 174 if not isinstance(series, Series): 175 raise TypeError("The series argument must be a pandas Series") 176 if not isinstance(series.index, PeriodIndex): 177 raise TypeError("The series index must be a pandas PeriodIndex") 178 if series.empty: 179 raise ValueError("The series argument must not be empty") 180 if series.index.freqstr[0] not in ("Q", "M", "D"): 181 raise ValueError("The series index must have a frequency of Q, M, or D") 182 if series.index.has_duplicates: 183 raise ValueError("The series index must not have duplicate values") 184 185 # --- ensure the index is complete and the date is sorted 186 complete = period_range(start=series.index.min(), end=series.index.max()) 187 series = series.reindex(complete, fill_value=nan) 188 series = series.sort_index(ascending=True) 189 190 # --- calculate annual and periodic growth 191 ppy = {"Q": 4, "M": 12, "D": 365}[PeriodIndex(series.index).freqstr[:1]] 192 annual = series.pct_change(periods=ppy) * 100 193 periodic = series.pct_change(periods=1) * 100 194 periodic_name = {4: "Quarterly", 12: "Monthly", 365: "Daily"}[ppy] + " Growth" 195 return DataFrame( 196 { 197 "Annual Growth": annual, 198 periodic_name: periodic, 199 } 200 )
Calculate annual and periodic growth for a pandas Series, where the index is a PeriodIndex.
Args:
- series: A pandas Series with an appropriate PeriodIndex.
Returns a two column DataFrame:
Raises
- TypeError if the series is not a pandas Series.
- TypeError if the series index is not a PeriodIndex.
- ValueError if the series is empty.
- ValueError if the series index does not have a frequency of Q, M, or D.
- ValueError if the series index has duplicates.
def
growth_plot(data: ~DataT, **kwargs) -> matplotlib.axes._axes.Axes:
203def growth_plot( 204 data: DataT, 205 **kwargs, 206) -> Axes: 207 """ 208 Plot annual growth (as a line) and periodic growth (as bars) 209 on the same axes. 210 211 Args: 212 - data: A pandas DataFrame with two columns: 213 - kwargs: 214 # --- common options 215 ax: Axes | None -- the matplotlib Axes to plot on, or None to create a new one. 216 plot_from: Period | int | None -- the period to start plotting from 217 label_series: bool -- whether to label the series in the legend. 218 max_ticks: int -- maximum number of ticks on the x-axis 219 # --- options passed to the line plot 220 line_width: float | int -- the width of the line 221 line_color: str -- the color of the line 222 line_style: str -- the style of the line 223 annotate_line: None | bool -- whether to annotate the end of the line 224 line_rounding: bool | int -- rounding for line annotation 225 line_fontsize: str | int | float -- fontsize for the line annotation 226 line_fontname: str -- font name for the line annotation 227 line_anno_color: str | bool | None -- color for the line annotation 228 # --- options passed to the bar plot 229 bar_width: float, 230 bar_color: str, 231 annotate_bars: None | bool -- whether to annotate the bars 232 above: bool -- whether to place the bar annotations above the bars 233 bar_fontsize: str | int | float -- fontsize for the bar annotations 234 bar_fontname: str -- font name for the bar annotations 235 bar_rounding: bool | int -- rounding for bar annotation 236 bar_anno_color: str | None -- color for the bar annotation 237 bar_rotation: int | float -- rotation for the bar annotation 238 } 239 Returns: 240 - axes: The matplotlib Axes object. 241 242 Raises: 243 - TypeError if the annual and periodic arguments are not pandas Series. 244 - TypeError if the annual index is not a PeriodIndex. 245 - ValueError if the annual and periodic series do not have the same index. 246 """ 247 248 # --- check the kwargs 249 me = "growth_plot" 250 report_kwargs(called_from=me, **kwargs) 251 kwargs = validate_kwargs(GROWTH_KW_TYPES, me, **kwargs) 252 253 # --- data checks 254 data = check_clean_timeseries(data, me) 255 if len(data.columns) != 2: 256 raise TypeError("The data argument must be a pandas DataFrame with two columns") 257 data, kwargs = constrain_data(data, **kwargs) 258 259 # --- get the series of interest ... 260 annual = data[data.columns[0]] 261 periodic = data[data.columns[1]] 262 263 # --- series names 264 annual.name = "Annual Growth" 265 periodic.name = {"M": "Monthly", "Q": "Quarterly", "D": "Daily"}[ 266 PeriodIndex(periodic.index).freqstr[:1] 267 ] + " Growth" 268 269 # --- convert PeriodIndex periodic growth data to integer indexed data. 270 saved_pi = map_periodindex(periodic) 271 if saved_pi is not None: 272 periodic = saved_pi[0] # extract the reindexed DataFrame 273 274 # --- simple bar chart for the periodic growth 275 if BAR_ANNO_COLOR not in kwargs or kwargs[BAR_ANNO_COLOR] is None: 276 kwargs[BAR_ANNO_COLOR] = "black" if kwargs.get(ABOVE, False) else "white" 277 selected = package_kwargs(to_bar_plot, **kwargs) 278 axes = bar_plot(periodic, **selected) 279 280 # --- and now the annual growth as a line 281 selected = package_kwargs(to_line_plot, **kwargs) 282 line_plot(annual, ax=axes, **selected) 283 284 # --- fix the x-axis labels 285 if saved_pi is not None: 286 set_labels(axes, saved_pi[1], kwargs.get("max_ticks", 10)) 287 288 # --- and done ... 289 return axes
Plot annual growth (as a line) and periodic growth (as bars) on the same axes.
Args:
- data: A pandas DataFrame with two columns:
- kwargs:
# --- common options
ax: Axes | None -- the matplotlib Axes to plot on, or None to create a new one.
plot_from: Period | int | None -- the period to start plotting from
label_series: bool -- whether to label the series in the legend.
max_ticks: int -- maximum number of ticks on the x-axis
# --- options passed to the line plot
line_width: float | int -- the width of the line
line_color: str -- the color of the line
line_style: str -- the style of the line
annotate_line: None | bool -- whether to annotate the end of the line
line_rounding: bool | int -- rounding for line annotation
line_fontsize: str | int | float -- fontsize for the line annotation
line_fontname: str -- font name for the line annotation
line_anno_color: str | bool | None -- color for the line annotation
# --- options passed to the bar plot
bar_width: float,
bar_color: str,
annotate_bars: None | bool -- whether to annotate the bars
above: bool -- whether to place the bar annotations above the bars
bar_fontsize: str | int | float -- fontsize for the bar annotations
bar_fontname: str -- font name for the bar annotations
bar_rounding: bool | int -- rounding for bar annotation
bar_anno_color: str | None -- color for the bar annotation
bar_rotation: int | float -- rotation for the bar annotation
} Returns: - axes: The matplotlib Axes object.
Raises:
- TypeError if the annual and periodic arguments are not pandas Series.
- TypeError if the annual index is not a PeriodIndex.
- ValueError if the annual and periodic series do not have the same index.
def
series_growth_plot(data: ~DataT, **kwargs) -> matplotlib.axes._axes.Axes:
292def series_growth_plot( 293 data: DataT, 294 **kwargs, 295) -> Axes: 296 """ 297 Plot annual and periodic growth in percentage terms from 298 a pandas Series, and finalise the plot. 299 300 Args: 301 - data: A pandas Series with an appropriate PeriodIndex. 302 - kwargs: 303 - takes the same kwargs as for growth_plot() 304 """ 305 306 # --- check the kwargs 307 me = "series_growth_plot" 308 report_kwargs(called_from=me, **kwargs) 309 kwargs = validate_kwargs(SERIES_GROWTH_KW_TYPES, me, **kwargs) 310 311 # --- sanity checks 312 if not isinstance(data, Series): 313 raise TypeError( 314 "The data argument to series_growth_plot() must be a pandas Series" 315 ) 316 317 # --- calculate growth and plot - add ylabel 318 ylabel: str | None = kwargs.pop("ylabel", None) 319 if ylabel is not None: 320 print(f"Did you intend to specify a value for the 'ylabel' in {me}()?") 321 ylabel = "Growth (%)" if ylabel is None else ylabel 322 growth = calc_growth(data) 323 ax = growth_plot(growth, **kwargs) 324 ax.set_ylabel(ylabel) 325 return ax
Plot annual and periodic growth in percentage terms from a pandas Series, and finalise the plot.
Args:
- data: A pandas Series with an appropriate PeriodIndex.
- kwargs:
- takes the same kwargs as for growth_plot()