bumplot 0.1.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {bumplot-0.1.0 → bumplot-0.2.1}/.github/workflows/tests.yaml +1 -2
  2. {bumplot-0.1.0 → bumplot-0.2.1}/.gitignore +2 -1
  3. {bumplot-0.1.0 → bumplot-0.2.1}/LICENSE +1 -1
  4. {bumplot-0.1.0 → bumplot-0.2.1}/PKG-INFO +18 -12
  5. {bumplot-0.1.0 → bumplot-0.2.1}/README.md +15 -9
  6. bumplot-0.2.1/README_files/figure-commonmark/cell-3-output-1.png +0 -0
  7. bumplot-0.2.1/bumplot/__init__.py +5 -0
  8. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot/_utils.py +10 -11
  9. bumplot-0.2.1/bumplot/main.py +131 -0
  10. bumplot-0.2.1/bumplot/opts.py +191 -0
  11. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot.egg-info/PKG-INFO +18 -12
  12. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot.egg-info/SOURCES.txt +7 -3
  13. {bumplot-0.1.0 → bumplot-0.2.1}/docs/README.qmd +22 -4
  14. bumplot-0.2.1/docs/advanced-usage.md +231 -0
  15. {bumplot-0.1.0 → bumplot-0.2.1}/docs/contributing.md +4 -2
  16. bumplot-0.2.1/docs/data/water-africa.csv +7 -0
  17. {bumplot-0.1.0 → bumplot-0.2.1}/docs/examples.md +59 -20
  18. {bumplot-0.1.0 → bumplot-0.2.1}/docs/index.md +9 -4
  19. bumplot-0.1.0/Makefile → bumplot-0.2.1/justfile +0 -2
  20. {bumplot-0.1.0 → bumplot-0.2.1}/mkdocs.yaml +1 -0
  21. {bumplot-0.1.0 → bumplot-0.2.1}/pyproject.toml +6 -4
  22. bumplot-0.2.1/tests/test_main.py +196 -0
  23. bumplot-0.2.1/tests/test_opts.py +108 -0
  24. bumplot-0.1.0/README_files/figure-commonmark/cell-2-output-1.png +0 -0
  25. bumplot-0.1.0/bumplot/__init__.py +0 -4
  26. bumplot-0.1.0/bumplot/main.py +0 -104
  27. bumplot-0.1.0/tests/test_main.py +0 -74
  28. {bumplot-0.1.0 → bumplot-0.2.1}/.coverage +0 -0
  29. {bumplot-0.1.0 → bumplot-0.2.1}/.github/workflows/doc.yaml +0 -0
  30. {bumplot-0.1.0 → bumplot-0.2.1}/.github/workflows/lint.yaml +0 -0
  31. {bumplot-0.1.0 → bumplot-0.2.1}/.github/workflows/pypi.yaml +0 -0
  32. {bumplot-0.1.0 → bumplot-0.2.1}/.github/workflows/type.yaml +0 -0
  33. {bumplot-0.1.0 → bumplot-0.2.1}/.pre-commit-config.yaml +0 -0
  34. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot/bezier.py +0 -0
  35. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot.egg-info/dependency_links.txt +0 -0
  36. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot.egg-info/requires.txt +0 -0
  37. {bumplot-0.1.0 → bumplot-0.2.1}/bumplot.egg-info/top_level.txt +0 -0
  38. {bumplot-0.1.0 → bumplot-0.2.1}/coverage-badge.svg +0 -0
  39. {bumplot-0.1.0 → bumplot-0.2.1}/docs/.gitignore +0 -0
  40. {bumplot-0.1.0 → bumplot-0.2.1}/docs/reference/bezier.md +0 -0
  41. {bumplot-0.1.0 → bumplot-0.2.1}/docs/reference/bumplot.md +0 -0
  42. {bumplot-0.1.0 → bumplot-0.2.1}/docs/stylesheets/style.css +0 -0
  43. {bumplot-0.1.0 → bumplot-0.2.1}/overrides/partials/footer.html +0 -0
  44. {bumplot-0.1.0 → bumplot-0.2.1}/setup.cfg +0 -0
  45. {bumplot-0.1.0 → bumplot-0.2.1}/tests/__init__.py +0 -0
@@ -10,8 +10,7 @@ jobs:
10
10
  strategy:
11
11
  matrix:
12
12
  python-version:
13
- - "3.11"
14
- - "3.12"
13
+ - "3.10"
15
14
  - "3.13"
16
15
  env:
17
16
  UV_PYTHON: ${{ matrix.python-version }}
@@ -20,4 +20,5 @@ env/
20
20
 
21
21
  *.zip
22
22
  sandbox/
23
- scripts/release.sh
23
+ release.sh
24
+ .claude/
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) Year Name
3
+ Copyright (c) 2025 Joseph Barbier
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bumplot
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: Easily create and customize bump charts in Python
5
5
  Author-email: Joseph Barbier <joseph.barbierdarnal@gmail.com>
6
6
  License-Expression: MIT
@@ -8,10 +8,10 @@ Project-URL: Homepage, https://y-sunflower.github.io/bumplot/
8
8
  Project-URL: Issues, https://github.com/y-sunflower/bumplot/issues
9
9
  Project-URL: Documentation, https://y-sunflower.github.io/bumplot/
10
10
  Project-URL: Repository, https://github.com/y-sunflower/bumplot
11
- Keywords: bump,bump plot,bump charts,matplotlib,data,visualization
11
+ Keywords: bump,bump plot,bump charts,matplotlib,data,visualization,bezier,curve
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Operating System :: OS Independent
14
- Classifier: Development Status :: 4 - Beta
14
+ Classifier: Development Status :: 5 - Production/Stable
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
@@ -19,12 +19,10 @@ Requires-Dist: matplotlib>=3.9.4
19
19
  Requires-Dist: narwhals>=2.0.0
20
20
  Dynamic: license-file
21
21
 
22
-
22
+ # `bumplot`: easily create and customize bump charts in Python
23
23
 
24
24
  <!-- Automatically generated, uses README.qmd to modify README.md -->
25
25
 
26
- # `bumplot`: easily create and customize bump charts in Python
27
-
28
26
  <img src="https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/bumplot/image.png?raw=true" alt="bumplot logo" align="right" width="180px"/>
29
27
 
30
28
  `bumplot` is a small Python package made to facilitate the creation of
@@ -42,7 +40,7 @@ documentation](https://y-sunflower.github.io/bumplot/)
42
40
 
43
41
  ## Get started
44
42
 
45
- ``` python
43
+ ```python
46
44
  import matplotlib.pyplot as plt
47
45
  import pandas as pd
48
46
 
@@ -56,13 +54,11 @@ data = pd.DataFrame(
56
54
  "C": [90, 20, 70, 40],
57
55
  }
58
56
  )
59
- x = "x"
60
- y_columns = ["A", "B", "C"]
61
57
 
62
58
  fig, ax = plt.subplots(figsize=(8, 4))
63
59
  bumplot(
64
- x=x,
65
- y_columns=y_columns,
60
+ x="x",
61
+ y_columns=["A", "B", "C"],
66
62
  data=data,
67
63
  curve_force=0.5,
68
64
  plot_kwargs={"lw": 4},
@@ -74,7 +70,7 @@ ax.spines[["top", "right", "left", "bottom"]].set_visible(False)
74
70
  ax.grid(alpha=0.4)
75
71
  ```
76
72
 
77
- ![](README_files/figure-commonmark/cell-2-output-1.png)
73
+ ![](README_files/figure-commonmark/cell-3-output-1.png)
78
74
 
79
75
  [See more examples](https://y-sunflower.github.io/bumplot/examples/)
80
76
 
@@ -83,3 +79,13 @@ ax.grid(alpha=0.4)
83
79
  ## Installation
84
80
 
85
81
  pip install bumplot
82
+
83
+ <br><br>
84
+
85
+ ## Features
86
+
87
+ - Automatic ranking of your data (with support for both `pandas` and
88
+ `polars`)
89
+ - Accept categorical data for x-axis
90
+ - Infinite customization capabilities
91
+ - Easy control of the curvature intensity
@@ -1,9 +1,7 @@
1
-
1
+ # `bumplot`: easily create and customize bump charts in Python
2
2
 
3
3
  <!-- Automatically generated, uses README.qmd to modify README.md -->
4
4
 
5
- # `bumplot`: easily create and customize bump charts in Python
6
-
7
5
  <img src="https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/bumplot/image.png?raw=true" alt="bumplot logo" align="right" width="180px"/>
8
6
 
9
7
  `bumplot` is a small Python package made to facilitate the creation of
@@ -21,7 +19,7 @@ documentation](https://y-sunflower.github.io/bumplot/)
21
19
 
22
20
  ## Get started
23
21
 
24
- ``` python
22
+ ```python
25
23
  import matplotlib.pyplot as plt
26
24
  import pandas as pd
27
25
 
@@ -35,13 +33,11 @@ data = pd.DataFrame(
35
33
  "C": [90, 20, 70, 40],
36
34
  }
37
35
  )
38
- x = "x"
39
- y_columns = ["A", "B", "C"]
40
36
 
41
37
  fig, ax = plt.subplots(figsize=(8, 4))
42
38
  bumplot(
43
- x=x,
44
- y_columns=y_columns,
39
+ x="x",
40
+ y_columns=["A", "B", "C"],
45
41
  data=data,
46
42
  curve_force=0.5,
47
43
  plot_kwargs={"lw": 4},
@@ -53,7 +49,7 @@ ax.spines[["top", "right", "left", "bottom"]].set_visible(False)
53
49
  ax.grid(alpha=0.4)
54
50
  ```
55
51
 
56
- ![](README_files/figure-commonmark/cell-2-output-1.png)
52
+ ![](README_files/figure-commonmark/cell-3-output-1.png)
57
53
 
58
54
  [See more examples](https://y-sunflower.github.io/bumplot/examples/)
59
55
 
@@ -62,3 +58,13 @@ ax.grid(alpha=0.4)
62
58
  ## Installation
63
59
 
64
60
  pip install bumplot
61
+
62
+ <br><br>
63
+
64
+ ## Features
65
+
66
+ - Automatic ranking of your data (with support for both `pandas` and
67
+ `polars`)
68
+ - Accept categorical data for x-axis
69
+ - Infinite customization capabilities
70
+ - Easy control of the curvature intensity
@@ -0,0 +1,5 @@
1
+ from .main import bumplot
2
+ from .opts import opts, opts_from_color
3
+
4
+ __version__ = "0.2.1"
5
+ __all__ = ["bumplot", "opts", "opts_from_color"]
@@ -1,17 +1,7 @@
1
- import matplotlib.pyplot as plt
2
-
3
1
  import narwhals as nw
4
2
  from narwhals.typing import IntoDataFrame
5
3
 
6
4
 
7
- def _get_first_n_colors(n=int) -> list[str]:
8
- """
9
- Get the first n colors from matplotlib rcParams.
10
- """
11
- colors: list[str] = plt.rcParams["axes.prop_cycle"].by_key()["color"][:n]
12
- return colors
13
-
14
-
15
5
  def _ranked_df(df: IntoDataFrame, x: str, y_columns: list[str]):
16
6
  """
17
7
  Convert a dataframe to a ranked version of it.
@@ -20,9 +10,18 @@ def _ranked_df(df: IntoDataFrame, x: str, y_columns: list[str]):
20
10
 
21
11
  df_native_ranked = (
22
12
  df_native.unpivot(on=y_columns, index=x)
23
- .with_columns(nw.col("value").rank("ordinal").over(x))
13
+ .with_columns(nw.col("value").rank("ordinal", descending=True).over(x))
24
14
  .pivot(on="variable", index=x, values="value")
25
15
  .select(nw.col(x), nw.col(y_columns))
26
16
  )
27
17
 
28
18
  return df_native_ranked
19
+
20
+
21
+ def _to_ordinal(n: int) -> str:
22
+ """Convert number to ordinal string (1 -> '1st', 2 -> '2nd', etc.)"""
23
+ if 11 <= n % 100 <= 13:
24
+ suffix = "th"
25
+ else:
26
+ suffix = {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
27
+ return f"{n}{suffix}"
@@ -0,0 +1,131 @@
1
+ from collections import ChainMap
2
+ from itertools import cycle
3
+
4
+ import matplotlib.pyplot as plt
5
+ from matplotlib.axes import Axes
6
+ from matplotlib.path import Path
7
+ import matplotlib.patches as patches
8
+ from matplotlib.cbook import normalize_kwargs
9
+ from matplotlib.collections import PathCollection
10
+ from matplotlib.patches import PathPatch
11
+
12
+ import numpy as np
13
+
14
+ from narwhals.typing import IntoDataFrame
15
+
16
+ from .bezier import bezier_curve
17
+ from ._utils import _ranked_df, _to_ordinal
18
+ from .opts import BumpOpts, _get_plot_kwargs, _get_scatter_kwargs
19
+
20
+ from typing import Any, Iterable, Tuple
21
+
22
+
23
+ def bumplot(
24
+ x: str,
25
+ y_columns: Iterable[str | tuple[str, BumpOpts]],
26
+ data: IntoDataFrame,
27
+ curve_force: float = 1,
28
+ invert_y_axis: bool = True,
29
+ colors: Iterable[str] | None = None,
30
+ plot_kwargs: dict[str, Any] = {},
31
+ scatter_kwargs: dict[str, Any] = {},
32
+ ax: Axes | None = None,
33
+ ordinal_labels: bool = False,
34
+ ) -> Tuple[Axes, dict[str, Tuple[PathPatch, PathCollection]]]:
35
+ """
36
+ Creates bump plot, or bump chart, from multiple numerical
37
+ columns.
38
+
39
+ It requires the data to be in wide format (e.g., one column
40
+ per line you want to plot).
41
+
42
+ Args:
43
+ x: colname of the x-axis variable
44
+ y_columns: colnames of the y-axis variables and their plotting options.
45
+ data: A dataframe
46
+ curve_force: Smoothing factor controlling curve tightness. Higher
47
+ values increase curvature by moving control points further away
48
+ from the anchors.
49
+ invert_y_axis: Whether to invert y axis
50
+ colors: An optional list of colors
51
+ plot_kwargs: Additional arguments passed to `patches.PathPatch()`
52
+ scatter_kwargs: Additional arguments passed to `scatter()`
53
+ ax: The matplotlib Axes used. Default to `plt.gca()`
54
+ ordinal_labels: If True, converts y-axis labels to ordinal numbers (1st, 2nd, 3rd, etc.)
55
+ Returns:
56
+ The matplotlib Axes with the bump plot
57
+ """
58
+ _plot_ax: Axes = ax if ax is not None else plt.gca()
59
+ colors_iterable = (
60
+ colors
61
+ if colors is not None
62
+ else plt.rcParams["axes.prop_cycle"].by_key()["color"]
63
+ )
64
+
65
+ y_bumps: list[tuple[str, BumpOpts]] = [
66
+ (y, BumpOpts()) if isinstance(y, str) else y for y in y_columns
67
+ ]
68
+ ranked: IntoDataFrame = _ranked_df(data, x=x, y_columns=[y for y, _ in y_bumps])
69
+ x_values_raw: np.ndarray = np.ravel(ranked.select(x).to_numpy())
70
+
71
+ if np.issubdtype(x_values_raw.dtype, np.number):
72
+ x_values = x_values_raw
73
+ x_labels = x_values_raw
74
+ else:
75
+ uniques = list(dict.fromkeys(x_values_raw)) # preserves order
76
+ mapping = {val: i for i, val in enumerate(uniques)}
77
+ x_values = np.array([mapping[val] for val in x_values_raw], dtype=int)
78
+ x_labels = x_values_raw
79
+
80
+ artists = {}
81
+ for (name, bump_opts), color in zip(y_bumps, cycle(colors_iterable)):
82
+ y_values: np.ndarray = np.ravel(ranked.select(name).to_numpy())
83
+ vertices, codes = bezier_curve(
84
+ x=x_values,
85
+ y=y_values,
86
+ force=curve_force,
87
+ )
88
+
89
+ path: Path = Path(vertices=vertices, codes=codes)
90
+ patch: PathPatch = patches.PathPatch(
91
+ path=path,
92
+ facecolor="none",
93
+ **ChainMap(
94
+ _get_plot_kwargs(bump_opts),
95
+ normalize_kwargs(plot_kwargs, PathPatch),
96
+ {"edgecolor": color},
97
+ ),
98
+ )
99
+ _plot_ax.add_patch(patch)
100
+
101
+ scatter = _plot_ax.scatter(
102
+ x_values,
103
+ y_values,
104
+ label=name,
105
+ **ChainMap(
106
+ _get_scatter_kwargs(bump_opts),
107
+ normalize_kwargs(scatter_kwargs, PathCollection),
108
+ {"facecolor": color},
109
+ ),
110
+ )
111
+ artists[name] = (patch, scatter)
112
+
113
+ ticks: list[int] = list(range(1, len(y_bumps) + 1))
114
+
115
+ if invert_y_axis:
116
+ _plot_ax.invert_yaxis()
117
+ else:
118
+ ticks: list[int] = list(reversed(ticks))
119
+
120
+ _plot_ax.set_yticks(ticks=ticks)
121
+
122
+ labels = (
123
+ [_to_ordinal(tick) for tick in ticks]
124
+ if ordinal_labels
125
+ else [str(tick) for tick in ticks]
126
+ )
127
+ _plot_ax.set_yticklabels(labels)
128
+
129
+ _plot_ax.set_xticks(ticks=np.unique(x_values), labels=np.unique(x_labels))
130
+
131
+ return _plot_ax, artists
@@ -0,0 +1,191 @@
1
+ from typing import Any, TypedDict
2
+
3
+
4
+ class BumpOpts(TypedDict, total=False):
5
+ """
6
+ Typed dictionary describing high-level styling options for a bump plot.
7
+
8
+ This type represents a user-facing, backend-agnostic set of visual options
9
+ that can be applied to both line (plot) and marker (scatter) artists.
10
+
11
+ All fields are optional. Keys are validated at runtime when constructed via
12
+ `opts()` to ensure only supported options are provided.
13
+
14
+ The options are later translated into Matplotlib-specific keyword arguments
15
+ via `_get_plot_kwargs()` and `_get_scatter_kwargs()`.
16
+
17
+ Notes
18
+ -----
19
+ - Keys prefixed with `line_` apply to line artists.
20
+ - Keys prefixed with `marker_` apply to scatter/marker artists.
21
+ - Some options (e.g. `clip_on` and `zorder`) apply to both.
22
+ """
23
+
24
+ line_alpha: float
25
+ line_color: str
26
+ line_style: str
27
+ line_width: float
28
+
29
+ marker: str
30
+ marker_size: float
31
+ marker_alpha: float
32
+ marker_facecolor: str
33
+ marker_edgecolor: str
34
+ marker_edgewidth: float
35
+
36
+ clip_on: bool
37
+ zorder: int
38
+
39
+
40
+ PLOT_MAPPINGS: dict[str, str] = {
41
+ "line_alpha": "alpha",
42
+ "line_color": "edgecolor",
43
+ "line_style": "linestyle",
44
+ "line_width": "linewidth",
45
+ "clip_on": "clip_on",
46
+ "zorder": "zorder",
47
+ }
48
+
49
+ SCATTER_MAPPINGS: dict[str, str] = {
50
+ "marker": "marker",
51
+ "marker_alpha": "alpha",
52
+ "marker_edgecolor": "edgecolor",
53
+ "marker_edgewidth": "linewidth",
54
+ "marker_facecolor": "facecolor",
55
+ "marker_size": "s",
56
+ "clip_on": "clip_on",
57
+ "zorder": "zorder",
58
+ }
59
+
60
+
61
+ # TODO: For >=Python 3.11 (https://docs.python.org/3/library/typing.html#typing.Unpack)
62
+ def opts(**kwargs: Any) -> BumpOpts:
63
+ """
64
+ Construct a validated `BumpOpts` mapping from keyword arguments.
65
+
66
+ This function enforces that all provided keyword arguments correspond to
67
+ supported `BumpOpts` fields. Any unexpected keys result in a `TypeError`.
68
+
69
+ Parameters
70
+ ----------
71
+ **kwargs: Unpack[BumpOpts]
72
+ Keyword arguments corresponding to fields defined on `BumpOpts`.
73
+
74
+ Returns
75
+ -------
76
+ BumpOpts
77
+ A typed dictionary containing the validated bump plot options.
78
+
79
+ Raises
80
+ ------
81
+ TypeError
82
+ If one or more unsupported keyword arguments are provided.
83
+
84
+ Notes
85
+ -----
86
+ This function exists to provide runtime validation for `BumpOpts`,
87
+ which is otherwise only enforced statically by type checkers.
88
+ """
89
+ unsupported_keys = kwargs.keys() - BumpOpts.__annotations__
90
+ if unsupported_keys:
91
+ unsupported_repr = ", ".join(map(repr, sorted(unsupported_keys)))
92
+ msg = f"BumpOpts got unexpected keyword argument(s): {unsupported_repr}"
93
+ raise TypeError(msg)
94
+
95
+ return BumpOpts(**kwargs)
96
+
97
+
98
+ def opts_from_color(color, /, **kwargs: Any) -> BumpOpts:
99
+ """
100
+ Construct a `BumpOpts` mapping using a single color applied consistently
101
+ across line and marker components.
102
+
103
+ The provided color is applied to:
104
+ - `line_color`
105
+ - `marker_facecolor`
106
+ - `marker_edgecolor`
107
+
108
+ Any explicitly provided keyword arguments take precedence over the color-based
109
+ defaults.
110
+
111
+ Parameters
112
+ ----------
113
+ color
114
+ The color to apply to line and marker components.
115
+ **kwargs
116
+ Additional or overriding bump plot options (passed to `opts`).
117
+
118
+ Returns
119
+ -------
120
+ BumpOpts
121
+ A validated bump plot options mapping.
122
+
123
+ See Also
124
+ --------
125
+ opts: Performs keyword validation and construction.
126
+ """
127
+ overrides = ["line_color", "marker_facecolor", "marker_edgecolor"]
128
+ new_kwargs = {k: color for k in overrides} | kwargs
129
+ return opts(**new_kwargs)
130
+
131
+
132
+ def _get_plot_kwargs(kwargs: BumpOpts, /) -> dict[str, Any]:
133
+ """
134
+ Extract Matplotlib `plot` keyword arguments from a `BumpOpts` mapping.
135
+
136
+ This function translates bump-plot-specific option names into the equivalent
137
+ Matplotlib `Axes.plot` keyword arguments using `bumplot.opts.PLOT_MAPPINGS`.
138
+
139
+ Parameters
140
+ ----------
141
+ kwargs: Unpack[BumpOpts]
142
+ A `BumpOpts` mapping containing zero or more plot-related options.
143
+
144
+ Returns
145
+ -------
146
+ dict[str, Any]
147
+ A dictionary of Matplotlib-compatible keyword arguments suitable for
148
+ `Axes.patches.PathPatch`.
149
+
150
+ Notes
151
+ -----
152
+ - Only keys present in both `kwargs` and `PLOT_MAPPINGS` are included.
153
+ """
154
+ plot_kwargs = {}
155
+ for bump_arg, mpl_arg in PLOT_MAPPINGS.items():
156
+ try:
157
+ plot_kwargs[mpl_arg] = kwargs[bump_arg] # type: ignore[invalid-key]
158
+ except KeyError:
159
+ pass
160
+ return plot_kwargs
161
+
162
+
163
+ def _get_scatter_kwargs(kwargs: BumpOpts, /) -> dict[str, Any]:
164
+ """
165
+ Extract Matplotlib `scatter` keyword arguments from a `BumpOpts` mapping.
166
+
167
+ This function translates bump-plot-specific option names into the equivalent
168
+ Matplotlib `Axes.scatter` keyword arguments using `bumplot.opts.SCATTER_MAPPINGS`.
169
+
170
+ Parameters
171
+ ----------
172
+ kwargs: Unpack[BumpOpts]
173
+ A `BumpOpts` mapping containing zero or more plot-related options.
174
+
175
+ Returns
176
+ -------
177
+ dict[str, Any]
178
+ A dictionary of Matplotlib-compatible keyword arguments suitable for
179
+ `Axes.scatter`.
180
+
181
+ Notes
182
+ -----
183
+ - Only keys present in both `kwargs` and `SCATTER_MAPPINGS` are included.
184
+ """
185
+ scatter_kwargs = {}
186
+ for bump_arg, mpl_arg in SCATTER_MAPPINGS.items():
187
+ try:
188
+ scatter_kwargs[mpl_arg] = kwargs[bump_arg] # type: ignore[invalid-key]
189
+ except KeyError:
190
+ pass
191
+ return scatter_kwargs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bumplot
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: Easily create and customize bump charts in Python
5
5
  Author-email: Joseph Barbier <joseph.barbierdarnal@gmail.com>
6
6
  License-Expression: MIT
@@ -8,10 +8,10 @@ Project-URL: Homepage, https://y-sunflower.github.io/bumplot/
8
8
  Project-URL: Issues, https://github.com/y-sunflower/bumplot/issues
9
9
  Project-URL: Documentation, https://y-sunflower.github.io/bumplot/
10
10
  Project-URL: Repository, https://github.com/y-sunflower/bumplot
11
- Keywords: bump,bump plot,bump charts,matplotlib,data,visualization
11
+ Keywords: bump,bump plot,bump charts,matplotlib,data,visualization,bezier,curve
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Operating System :: OS Independent
14
- Classifier: Development Status :: 4 - Beta
14
+ Classifier: Development Status :: 5 - Production/Stable
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
@@ -19,12 +19,10 @@ Requires-Dist: matplotlib>=3.9.4
19
19
  Requires-Dist: narwhals>=2.0.0
20
20
  Dynamic: license-file
21
21
 
22
-
22
+ # `bumplot`: easily create and customize bump charts in Python
23
23
 
24
24
  <!-- Automatically generated, uses README.qmd to modify README.md -->
25
25
 
26
- # `bumplot`: easily create and customize bump charts in Python
27
-
28
26
  <img src="https://github.com/JosephBARBIERDARNAL/static/blob/main/python-libs/bumplot/image.png?raw=true" alt="bumplot logo" align="right" width="180px"/>
29
27
 
30
28
  `bumplot` is a small Python package made to facilitate the creation of
@@ -42,7 +40,7 @@ documentation](https://y-sunflower.github.io/bumplot/)
42
40
 
43
41
  ## Get started
44
42
 
45
- ``` python
43
+ ```python
46
44
  import matplotlib.pyplot as plt
47
45
  import pandas as pd
48
46
 
@@ -56,13 +54,11 @@ data = pd.DataFrame(
56
54
  "C": [90, 20, 70, 40],
57
55
  }
58
56
  )
59
- x = "x"
60
- y_columns = ["A", "B", "C"]
61
57
 
62
58
  fig, ax = plt.subplots(figsize=(8, 4))
63
59
  bumplot(
64
- x=x,
65
- y_columns=y_columns,
60
+ x="x",
61
+ y_columns=["A", "B", "C"],
66
62
  data=data,
67
63
  curve_force=0.5,
68
64
  plot_kwargs={"lw": 4},
@@ -74,7 +70,7 @@ ax.spines[["top", "right", "left", "bottom"]].set_visible(False)
74
70
  ax.grid(alpha=0.4)
75
71
  ```
76
72
 
77
- ![](README_files/figure-commonmark/cell-2-output-1.png)
73
+ ![](README_files/figure-commonmark/cell-3-output-1.png)
78
74
 
79
75
  [See more examples](https://y-sunflower.github.io/bumplot/examples/)
80
76
 
@@ -83,3 +79,13 @@ ax.grid(alpha=0.4)
83
79
  ## Installation
84
80
 
85
81
  pip install bumplot
82
+
83
+ <br><br>
84
+
85
+ ## Features
86
+
87
+ - Automatic ranking of your data (with support for both `pandas` and
88
+ `polars`)
89
+ - Accept categorical data for x-axis
90
+ - Infinite customization capabilities
91
+ - Easy control of the curvature intensity
@@ -2,9 +2,9 @@
2
2
  .gitignore
3
3
  .pre-commit-config.yaml
4
4
  LICENSE
5
- Makefile
6
5
  README.md
7
6
  coverage-badge.svg
7
+ justfile
8
8
  mkdocs.yaml
9
9
  pyproject.toml
10
10
  .github/workflows/doc.yaml
@@ -12,11 +12,12 @@ pyproject.toml
12
12
  .github/workflows/pypi.yaml
13
13
  .github/workflows/tests.yaml
14
14
  .github/workflows/type.yaml
15
- README_files/figure-commonmark/cell-2-output-1.png
15
+ README_files/figure-commonmark/cell-3-output-1.png
16
16
  bumplot/__init__.py
17
17
  bumplot/_utils.py
18
18
  bumplot/bezier.py
19
19
  bumplot/main.py
20
+ bumplot/opts.py
20
21
  bumplot.egg-info/PKG-INFO
21
22
  bumplot.egg-info/SOURCES.txt
22
23
  bumplot.egg-info/dependency_links.txt
@@ -24,12 +25,15 @@ bumplot.egg-info/requires.txt
24
25
  bumplot.egg-info/top_level.txt
25
26
  docs/.gitignore
26
27
  docs/README.qmd
28
+ docs/advanced-usage.md
27
29
  docs/contributing.md
28
30
  docs/examples.md
29
31
  docs/index.md
32
+ docs/data/water-africa.csv
30
33
  docs/reference/bezier.md
31
34
  docs/reference/bumplot.md
32
35
  docs/stylesheets/style.css
33
36
  overrides/partials/footer.html
34
37
  tests/__init__.py
35
- tests/test_main.py
38
+ tests/test_main.py
39
+ tests/test_opts.py