gsplot 0.0.1__py3-none-any.whl

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.
@@ -0,0 +1,289 @@
1
+ from typing import Any
2
+
3
+ import numpy as np
4
+ from matplotlib.axes import Axes
5
+ from matplotlib.collections import LineCollection
6
+ from matplotlib.colors import Normalize
7
+ from numpy.typing import ArrayLike, NDArray
8
+
9
+ from ..base.base import CreateClassParams, ParamsGetter, bind_passed_params
10
+ from ..base.base_alias_validator import AliasValidator
11
+ from ..figure.axes_base import AxesRangeSingleton, AxesResolver, AxisLayout
12
+ from ..style.legend_colormap import LegendColormap
13
+ from .line_colormap_base import LineColormapBase
14
+
15
+ __all__: list[str] = ["line_colormap_solid"]
16
+
17
+
18
+ class LineColormapSolid:
19
+ """
20
+ A class for plotting solid lines with a colormap applied along the line segments.
21
+
22
+ This class generates a single continuous line where the color is mapped to the
23
+ provided data using a colormap. It also supports interpolating points for smoother
24
+ color transitions.
25
+
26
+ Parameters
27
+ --------------------
28
+ axis_target : int or matplotlib.axes.Axes
29
+ The target axis for plotting. Can be an axis index or a Matplotlib `Axes` object.
30
+ x : ArrayLike
31
+ The x-coordinates of the line.
32
+ y : ArrayLike
33
+ The y-coordinates of the line.
34
+ cmapdata : ArrayLike
35
+ Data values used to map colors to the line segments.
36
+ cmap : str, optional
37
+ Name of the colormap to use (default is "viridis").
38
+ linewidth : int or float, optional
39
+ Width of the line (default is 1).
40
+ label : str or None, optional
41
+ Label for the line, used in legends (default is `None`).
42
+ interpolation_points : int or None, optional
43
+ Number of interpolation points for smooth color transitions (default is `None`).
44
+ **kwargs : Any
45
+ Additional keyword arguments passed to the `LegendColormap` class.
46
+
47
+ Attributes
48
+ --------------------
49
+ axis_index : int
50
+ The resolved index of the target axis.
51
+ axis : matplotlib.axes.Axes
52
+ The resolved target axis object.
53
+ x : numpy.ndarray
54
+ The x-coordinates as a NumPy array.
55
+ y : numpy.ndarray
56
+ The y-coordinates as a NumPy array.
57
+ cmapdata : numpy.ndarray
58
+ The colormap data as a NumPy array.
59
+
60
+ Methods
61
+ --------------------
62
+ add_legend_colormap()
63
+ Adds a legend entry for the colormap associated with the solid line.
64
+ normal_interpolate_points(interpolation_points)
65
+ Interpolates x, y, and colormap data for smoother color transitions.
66
+ plot()
67
+ Creates and plots the solid line with a colormap and returns the `LineCollection`.
68
+
69
+ Examples
70
+ --------------------
71
+ >>> x = [0, 1, 2, 3, 4]
72
+ >>> y = [1, 3, 2, 5, 4]
73
+ >>> cmapdata = [0.1, 0.3, 0.6, 0.9, 1.0]
74
+ >>> line = LineColormapSolid(axis_target=0, x=x, y=y, cmapdata=cmapdata, cmap="plasma")
75
+ >>> line.plot()
76
+ """
77
+
78
+ def __init__(
79
+ self,
80
+ axis_target: int | Axes,
81
+ x: ArrayLike,
82
+ y: ArrayLike,
83
+ cmapdata: ArrayLike,
84
+ cmap: str = "viridis",
85
+ linewidth: int | float = 1,
86
+ label: str | None = None,
87
+ interpolation_points: int | None = None,
88
+ **kwargs: Any,
89
+ ) -> None:
90
+ self.axis_target: int | Axes = axis_target
91
+
92
+ self.axis_index: int = AxesResolver(axis_target).axis_index
93
+ self.axis: Axes = AxesResolver(axis_target).axis
94
+
95
+ self._x: ArrayLike = x
96
+ self._y: ArrayLike = y
97
+ self._cmapdata: ArrayLike = cmapdata
98
+ self.cmap: str = cmap
99
+ self.linewidth = linewidth
100
+ self.label: str | None = label
101
+ self.interpolation_points: int | None = interpolation_points
102
+
103
+ self.kwargs: Any = kwargs
104
+
105
+ self.x: NDArray[Any] = np.array(self._x)
106
+ self.y: NDArray[Any] = np.array(self._y)
107
+ self.cmapdata: NDArray[Any] = np.array(self._cmapdata)
108
+
109
+ if self.label is not None:
110
+ self.add_legend_colormap()
111
+
112
+ def add_legend_colormap(self) -> None:
113
+ """
114
+ Adds a legend entry for the colormap associated with the solid line.
115
+
116
+ Determines the number of stripes in the colormap based on the interpolation
117
+ points or the colormap data length and adds a colormap patch to the legend.
118
+ """
119
+ if self.interpolation_points is None:
120
+ NUM_STRIPES = len(self.cmapdata)
121
+ else:
122
+ NUM_STRIPES = self.interpolation_points
123
+
124
+ # NUM_STRIPES in colormap should be subtracted by 1
125
+ NUM_STRIPES -= 1
126
+
127
+ LegendColormap(
128
+ self.axis_index,
129
+ self.cmap,
130
+ self.label,
131
+ NUM_STRIPES,
132
+ **self.kwargs,
133
+ ).axis_patch()
134
+
135
+ def normal_interpolate_points(self, interpolation_points: int) -> tuple:
136
+ """
137
+ Interpolates x, y, and colormap data to create smoother transitions.
138
+
139
+ Parameters
140
+ --------------------
141
+ interpolation_points : int
142
+ Number of points for interpolation.
143
+
144
+ Returns
145
+ --------------------
146
+ tuple
147
+ Interpolated x-coordinates, y-coordinates, and colormap data.
148
+ """
149
+ xdiff = np.diff(self.x)
150
+ ydiff = np.diff(self.y)
151
+ distances = np.sqrt(xdiff**2 + ydiff**2)
152
+ cumulative_distances = np.insert(np.cumsum(distances), 0, 0)
153
+ interpolated_distances = np.linspace(
154
+ 0, cumulative_distances[-1], interpolation_points
155
+ )
156
+
157
+ x_interpolated = np.interp(interpolated_distances, cumulative_distances, self.x)
158
+ y_interpolated = np.interp(interpolated_distances, cumulative_distances, self.y)
159
+
160
+ # Interpolate cmapdata
161
+ cmap_interpolated = np.interp(
162
+ interpolated_distances, cumulative_distances, self.cmapdata
163
+ )
164
+
165
+ return x_interpolated, y_interpolated, cmap_interpolated
166
+
167
+ @AxesRangeSingleton.update
168
+ def plot(self) -> list[LineCollection]:
169
+ """
170
+ Plots the solid line with a colormap applied to its segments.
171
+
172
+ This method interpolates points if required, creates line segments from the
173
+ data, and applies the colormap to the segments. The resulting line collection
174
+ is added to the axis.
175
+
176
+ Returns
177
+ --------------------
178
+ list[matplotlib.collections.LineCollection]
179
+ A list containing the single `LineCollection` object for the plotted solid line.
180
+
181
+ Notes
182
+ --------------------
183
+ This method is decorated with `@AxesRangeSingleton.update` to update the axis range.
184
+ """
185
+ if self.interpolation_points is not None:
186
+ self.x, self.y, self.cmapdata = self.normal_interpolate_points(
187
+ self.interpolation_points
188
+ )
189
+ segments: NDArray[np.float64] = LineColormapBase()._create_segment(
190
+ self.x, self.y
191
+ )
192
+ norm = LineColormapBase()._create_cmap(self.cmapdata)
193
+ print(norm)
194
+
195
+ lc: LineCollection = LineCollection(
196
+ segments.tolist(), cmap=self.cmap, norm=norm
197
+ )
198
+ lc.set_array(self.cmapdata)
199
+ lc.set_linewidth(self.linewidth)
200
+ lc.set_capstyle("projecting")
201
+ self.axis.add_collection(lc)
202
+
203
+ return [lc]
204
+
205
+
206
+ @bind_passed_params()
207
+ def line_colormap_solid(
208
+ axis_target: int | Axes,
209
+ x: ArrayLike,
210
+ y: ArrayLike,
211
+ cmapdata: ArrayLike,
212
+ cmap: str = "viridis",
213
+ linewidth: float | int = 1,
214
+ label: str | None = None,
215
+ interpolation_points: int | None = None,
216
+ **kwargs: Any,
217
+ ) -> list[LineCollection]:
218
+ """
219
+ Plots a solid line with a colormap applied along its segments.
220
+
221
+ This function creates a solid line on the specified axis with colors mapped
222
+ to the provided colormap data. It supports interpolation for smoother transitions
223
+ between segments.
224
+
225
+ Parameters
226
+ --------------------
227
+ axis_target : int or matplotlib.axes.Axes
228
+ The target axis for plotting. Can be an axis index or a Matplotlib `Axes` object.
229
+ x : ArrayLike
230
+ The x-coordinates of the line.
231
+ y : ArrayLike
232
+ The y-coordinates of the line.
233
+ cmapdata : ArrayLike
234
+ Data values used to map colors to the line segments.
235
+ cmap : str, optional
236
+ Name of the colormap to use (default is "viridis").
237
+ linewidth : float or int, optional
238
+ Width of the line (default is 1).
239
+ label : str or None, optional
240
+ Label for the line, used in legends (default is `None`).
241
+ interpolation_points : int or None, optional
242
+ Number of interpolation points for smooth color transitions (default is `None`).
243
+ **kwargs : Any
244
+ Additional keyword arguments passed to the `LegendColormap` class.
245
+
246
+ Notes
247
+ --------------------
248
+ - This function utilizes the `ParamsGetter` to retrieve bound parameters and the `CreateClassParams` class to handle the merging of default, configuration, and passed parameters.
249
+ - Alias validation is performed using the `AliasValidator` class.
250
+
251
+ - 'lw' (linewidth)
252
+
253
+ Returns
254
+ --------------------
255
+ list[matplotlib.collections.LineCollection]
256
+ A list containing the single `LineCollection` object for the plotted solid line.
257
+
258
+
259
+ Examples
260
+ --------------------
261
+ >>> import gsplot as gs
262
+ >>> x = [0, 1, 2, 3, 4]
263
+ >>> y = [1, 3, 2, 5, 4]
264
+ >>> cmapdata = [0.1, 0.3, 0.6, 0.9, 1.0]
265
+ >>> lc_list = gs.line_colormap_solid(axis_target=0, x=x, y=y, cmapdata=cmapdata, cmap="plasma")
266
+ >>> print(len(lc_list))
267
+ 1
268
+ """
269
+
270
+ alias_map = {
271
+ "lw": "linewidth",
272
+ }
273
+
274
+ passed_params: dict[str, Any] = ParamsGetter("passed_params").get_bound_params()
275
+ AliasValidator(alias_map, passed_params).validate()
276
+ class_params = CreateClassParams(passed_params).get_class_params()
277
+
278
+ _line_colormap_solid: LineColormapSolid = LineColormapSolid(
279
+ class_params["axis_target"],
280
+ class_params["x"],
281
+ class_params["y"],
282
+ class_params["cmapdata"],
283
+ class_params["cmap"],
284
+ class_params["linewidth"],
285
+ class_params["label"],
286
+ class_params["interpolation_points"],
287
+ **class_params["kwargs"],
288
+ )
289
+ return _line_colormap_solid.plot()
gsplot/plot/scatter.py ADDED
@@ -0,0 +1,228 @@
1
+ from typing import Any
2
+
3
+ import numpy as np
4
+ from matplotlib import colors
5
+ from matplotlib.axes import Axes
6
+ from matplotlib.collections import PathCollection
7
+ from matplotlib.typing import ColorType
8
+ from numpy.typing import ArrayLike, NDArray
9
+
10
+ from ..base.base import CreateClassParams, ParamsGetter, bind_passed_params
11
+ from ..base.base_alias_validator import AliasValidator
12
+ from ..figure.axes_base import AxesRangeSingleton, AxesResolver
13
+ from .line_base import AutoColor, NumLines
14
+
15
+ __all__: list[str] = ["scatter"]
16
+
17
+
18
+ class Scatter:
19
+ """
20
+ A class for creating scatter plots on a specified Matplotlib axis.
21
+
22
+ Parameters
23
+ --------------------
24
+ axis_target : int or matplotlib.axes.Axes
25
+ The target axis for the scatter plot. Can be an axis index or a Matplotlib `Axes` object.
26
+ x : ArrayLike
27
+ The x-coordinates of the scatter points.
28
+ y : ArrayLike
29
+ The y-coordinates of the scatter points.
30
+ color : ColorType or None, optional
31
+ Color of the points. If `None`, a default color from the axis's cycle is used (default is `None`).
32
+ size : int or float, optional
33
+ Size of the scatter points (default is 1).
34
+ alpha : int or float, optional
35
+ Opacity of the scatter points (default is 1).
36
+ **kwargs : Any
37
+ Additional keyword arguments passed to the `scatter` method of Matplotlib's `Axes`.
38
+
39
+ Attributes
40
+ --------------------
41
+ axis_index : int
42
+ The resolved index of the target axis.
43
+ axis : matplotlib.axes.Axes
44
+ The resolved target axis object.
45
+ x : numpy.ndarray
46
+ The x-coordinates as a NumPy array.
47
+ y : numpy.ndarray
48
+ The y-coordinates as a NumPy array.
49
+
50
+ Methods
51
+ --------------------
52
+ get_color() -> ColorType
53
+ Determines the color for the scatter points, either from the user input or the axis's color cycle.
54
+ plot() -> matplotlib.collections.PathCollection
55
+ Creates and plots the scatter points on the axis.
56
+
57
+ Examples
58
+ --------------------
59
+ >>> x = [1, 2, 3, 4]
60
+ >>> y = [10, 20, 15, 25]
61
+ >>> scatter = Scatter(axis_target=0, x=x, y=y, color="blue", size=10, alpha=0.5)
62
+ >>> scatter.plot()
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ axis_target: int | Axes,
68
+ x: ArrayLike,
69
+ y: ArrayLike,
70
+ color: ColorType | None = None,
71
+ size: int | float = 1,
72
+ alpha: int | float = 1,
73
+ **kwargs: Any,
74
+ ) -> None:
75
+ self.axis_target: int | Axes = axis_target
76
+
77
+ self.axis_index: int = AxesResolver(self.axis_target).axis_index
78
+ self.axis: Axes = AxesResolver(self.axis_target).axis
79
+
80
+ self._x: ArrayLike = x
81
+ self._y: ArrayLike = y
82
+ self._color: ColorType | None = color
83
+ self.size: int | float = size
84
+ self.alpha: int | float = alpha
85
+ self.kwargs: Any = kwargs
86
+
87
+ self.x: NDArray[Any] = np.array(self._x)
88
+ self.y: NDArray[Any] = np.array(self._y)
89
+
90
+ def get_color(self) -> ColorType:
91
+ """
92
+ Determines the color for the scatter points.
93
+
94
+ If a color is not explicitly provided, it retrieves a default color from the
95
+ axis's color cycle.
96
+
97
+ Returns
98
+ --------------------
99
+ ColorType
100
+ The resolved color for the scatter points.
101
+
102
+ Notes
103
+ --------------------
104
+ The method ensures compatibility with Matplotlib's color representation, converting
105
+ NumPy arrays to hexadecimal strings if needed.
106
+
107
+ Examples
108
+ --------------------
109
+ >>> scatter = Scatter(axis_target=0, x=[1, 2], y=[3, 4])
110
+ >>> scatter.get_color()
111
+ """
112
+ cycle_color: NDArray | str = AutoColor(self.axis_index).get_color()
113
+ if isinstance(cycle_color, np.ndarray):
114
+ cycle_color = colors.to_hex(
115
+ tuple(cycle_color)
116
+ ) # convert numpy array to tuple
117
+
118
+ default_color: ColorType = cycle_color if self._color is None else self._color
119
+ return default_color
120
+
121
+ @NumLines.count
122
+ @AxesRangeSingleton.update
123
+ def plot(self) -> PathCollection:
124
+ """
125
+ Plots the scatter points on the specified axis.
126
+
127
+ This method creates a scatter plot using the provided x, y, color, size, and alpha values.
128
+
129
+ Returns
130
+ --------------------
131
+ matplotlib.collections.PathCollection
132
+ The scatter plot as a PathCollection object.
133
+
134
+ Notes
135
+ --------------------
136
+ - This method is decorated with `@NumLines.count` to track the number of scatter calls on the axis.
137
+ - It is also decorated with `@AxesRangeSingleton.update` to update the axis range with the scatter data.
138
+
139
+ Examples
140
+ --------------------
141
+ >>> scatter = Scatter(axis_target=0, x=[1, 2, 3], y=[4, 5, 6], size=50, alpha=0.8)
142
+ >>> scatter.plot()
143
+ <matplotlib.collections.PathCollection>
144
+ """
145
+ _plot = self.axis.scatter(
146
+ self.x,
147
+ self.y,
148
+ s=self.size,
149
+ c=self.get_color(),
150
+ alpha=self.alpha,
151
+ **self.kwargs,
152
+ )
153
+ return _plot
154
+
155
+
156
+ @bind_passed_params()
157
+ def scatter(
158
+ axis_target: int | Axes,
159
+ x: ArrayLike,
160
+ y: ArrayLike,
161
+ color: ColorType | None = None,
162
+ size: int | float = 1,
163
+ alpha: int | float = 1,
164
+ **kwargs: Any,
165
+ ) -> PathCollection:
166
+ """
167
+ Creates a scatter plot on the specified axis.
168
+
169
+ This function uses the `Scatter` class to generate a scatter plot with customizable
170
+ size, color, and transparency.
171
+
172
+ Parameters
173
+ --------------------
174
+ axis_target : int or matplotlib.axes.Axes
175
+ The target axis for the scatter plot. Can be an axis index or a Matplotlib `Axes` object.
176
+ x : ArrayLike
177
+ The x-coordinates of the scatter points.
178
+ y : ArrayLike
179
+ The y-coordinates of the scatter points.
180
+ color : ColorType or None, optional
181
+ Color of the points. If `None`, a default color from the axis's cycle is used (default is `None`).
182
+ size : int or float, optional
183
+ Size of the scatter points (default is 1).
184
+ alpha : int or float, optional
185
+ Opacity of the scatter points (default is 1).
186
+ **kwargs : Any
187
+ Additional keyword arguments passed to the `scatter` method of Matplotlib's `Axes`.
188
+
189
+ Notes
190
+ --------------------
191
+ - This function utilizes the `ParamsGetter` to retrieve bound parameters and the `CreateClassParams` class to handle the merging of default, configuration, and passed parameters.
192
+ - Alias validation is performed using the `AliasValidator` class.
193
+
194
+ - 's' (size)
195
+ - 'c' (color)
196
+
197
+ Returns
198
+ --------------------
199
+ matplotlib.collections.PathCollection
200
+ The scatter plot as a PathCollection object.
201
+
202
+ Examples
203
+ --------------------
204
+ >>> import gsplot as gs
205
+ >>> x = [1, 2, 3, 4]
206
+ >>> y = [10, 20, 15, 25]
207
+ >>> gs.scatter(axis_target=0, x=x, y=y, color="red", size=20, alpha=0.8)
208
+ <matplotlib.collections.PathCollection>
209
+ """
210
+ alias_map = {
211
+ "s": "size",
212
+ "c": "color",
213
+ }
214
+
215
+ passed_params: dict[str, Any] = ParamsGetter("passed_params").get_bound_params()
216
+ AliasValidator(alias_map, passed_params).validate()
217
+ class_params: dict[str, Any] = CreateClassParams(passed_params).get_class_params()
218
+
219
+ _scatter = Scatter(
220
+ class_params["axis_target"],
221
+ class_params["x"],
222
+ class_params["y"],
223
+ class_params["color"],
224
+ class_params["size"],
225
+ class_params["alpha"],
226
+ **class_params["kwargs"],
227
+ )
228
+ return _scatter.plot()