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