dataplot 0.1.6__tar.gz → 0.1.7__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 (26) hide show
  1. {dataplot-0.1.6 → dataplot-0.1.7}/PKG-INFO +7 -2
  2. {dataplot-0.1.6 → dataplot-0.1.7}/README.md +5 -0
  3. {dataplot-0.1.6 → dataplot-0.1.7}/pyproject.toml +2 -2
  4. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/container.py +43 -23
  5. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/core.py +39 -12
  6. {dataplot-0.1.6 → dataplot-0.1.7}/.github/workflows/python-publish.yml +0 -0
  7. {dataplot-0.1.6 → dataplot-0.1.7}/.gitignore +0 -0
  8. {dataplot-0.1.6 → dataplot-0.1.7}/LICENSE +0 -0
  9. {dataplot-0.1.6 → dataplot-0.1.7}/examples/test.ipynb +0 -0
  10. {dataplot-0.1.6 → dataplot-0.1.7}/install.py +0 -0
  11. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/__init__.py +0 -0
  12. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/_typing.py +0 -0
  13. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/__init__.py +0 -0
  14. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/base.py +0 -0
  15. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/corrmap.py +0 -0
  16. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/histogram.py +0 -0
  17. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/ksplot.py +0 -0
  18. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/linechart.py +0 -0
  19. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/ppplot.py +0 -0
  20. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/qqplot.py +0 -0
  21. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/artist/scatterchart.py +0 -0
  22. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/dataset.py +0 -0
  23. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/setting.py +0 -0
  24. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/utils/__init__.py +0 -0
  25. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/utils/math.py +0 -0
  26. {dataplot-0.1.6 → dataplot-0.1.7}/src/dataplot/utils/multi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataplot
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Provides plotting tools useful in datascience.
5
5
  Project-URL: Documentation, https://github.com/Chitaoji/dataplot/blob/main/README.md
6
6
  Project-URL: Repository, https://github.com/Chitaoji/dataplot/
@@ -10,7 +10,7 @@ License-Expression: BSD-3-Clause
10
10
  License-File: LICENSE
11
11
  Keywords: plot
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Requires-Dist: lazyr
16
16
  Requires-Dist: matplotlib
@@ -51,6 +51,11 @@ seaborn
51
51
  This project falls under the BSD 3-Clause License.
52
52
 
53
53
  ## History
54
+ ### v0.1.7
55
+ * `dp.data(...)` can accept `PlotDataSet` objects now.
56
+ * `FigWrapper.__enter__()` now returns a copy safely via `_entered_copy`.
57
+ * Internal maintenance and stability refinements.
58
+
54
59
  ### v0.1.6
55
60
  * New method `PlotDataSet.scatter()` to draw true scatter charts while keeping `PlotDataSet.plot()` as line chart behavior.
56
61
  * Improved automatic label inference for `dp.data(...)`, plotting labels, and x-axis labels in interactive contexts.
@@ -28,6 +28,11 @@ seaborn
28
28
  This project falls under the BSD 3-Clause License.
29
29
 
30
30
  ## History
31
+ ### v0.1.7
32
+ * `dp.data(...)` can accept `PlotDataSet` objects now.
33
+ * `FigWrapper.__enter__()` now returns a copy safely via `_entered_copy`.
34
+ * Internal maintenance and stability refinements.
35
+
31
36
  ### v0.1.6
32
37
  * New method `PlotDataSet.scatter()` to draw true scatter charts while keeping `PlotDataSet.plot()` as line chart behavior.
33
38
  * Improved automatic label inference for `dp.data(...)`, plotting labels, and x-axis labels in interactive contexts.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dataplot"
7
- version = "0.1.6"
7
+ version = "0.1.7"
8
8
  dependencies = [
9
9
  "validating",
10
10
  "lazyr",
@@ -28,7 +28,7 @@ license-files = ["LICENSE"]
28
28
  keywords = ["plot"]
29
29
  classifiers = [
30
30
  "Programming Language :: Python :: 3",
31
- "Programming Language :: Python :: 3.12"
31
+ "Programming Language :: Python :: 3.13"
32
32
  ]
33
33
 
34
34
  [project.urls]
@@ -96,10 +96,10 @@ class FigWrapper(PlotSettable):
96
96
  nrows: int = 1
97
97
  ncols: int = 1
98
98
  active: bool = attr(repr=False, default=True)
99
- entered: bool = attr(init=False, repr=False, default=False)
100
99
  fig: Figure = attr(init=False, repr=False)
101
100
  axes: list[AxesWrapper] = attr(init=False, repr=False)
102
101
  artists: "list[Artist]" = attr(default_factory=list, init=False, repr=False)
102
+ _entered_copy: "FigWrapper | None" = attr(init=False, repr=False, default=None)
103
103
 
104
104
  def __enter__(self) -> Self:
105
105
  """
@@ -111,53 +111,61 @@ class FigWrapper(PlotSettable):
111
111
  An instance of self.
112
112
 
113
113
  """
114
- if not self.active:
115
- return self
116
- if self.entered:
114
+ if self._entered_copy is not None:
117
115
  raise DoubleEnteredError(
118
116
  f"can't enter an instance of {self.__class__.__name__!r} for twice; "
119
117
  "please do all the operations in one single context manager"
120
118
  )
121
119
 
122
- self.set_default(
120
+ figw = self.copy()
121
+ if not figw.active:
122
+ self._entered_copy = figw
123
+ return figw
124
+
125
+ figw.set_default(
123
126
  style="seaborn-v0_8-darkgrid",
124
- figsize=(10 * self.ncols, 5 * self.nrows),
127
+ figsize=(10 * figw.ncols, 5 * figw.nrows),
125
128
  subplots_adjust={"hspace": 0.5},
126
129
  fontdict={"fontsize": "x-large"},
127
130
  )
128
- plt.style.use(self.settings.style)
129
- self.fig, axes = plt.subplots(self.nrows, self.ncols)
130
- self.axes: list[AxesWrapper] = [AxesWrapper(x) for x in np.reshape(axes, -1)]
131
- self.entered = True
132
- return self
131
+ plt.style.use(figw.settings.style)
132
+ figw.fig, axes = plt.subplots(figw.nrows, figw.ncols)
133
+ figw.axes = [AxesWrapper(x) for x in np.reshape(axes, -1)]
134
+ self._entered_copy = figw
135
+ return figw
133
136
 
134
137
  def __exit__(self, *args) -> None:
135
138
  """
136
139
  Set various properties for the figure and paint it.
137
140
 
138
141
  """
139
- if not self.active:
142
+ figw = self._entered_copy
143
+ if figw is None:
144
+ figw = self
145
+
146
+ if not figw.active:
147
+ self._entered_copy = None
140
148
  return
141
149
 
142
- if len(self.axes) > 1:
143
- self.fig.suptitle(self.settings.title, **self.settings.fontdict)
150
+ if len(figw.axes) > 1:
151
+ figw.fig.suptitle(figw.settings.title, **figw.settings.fontdict)
144
152
  else:
145
- self.axes[0].ax.set_title(self.settings.title, **self.settings.fontdict)
153
+ figw.axes[0].ax.set_title(figw.settings.title, **figw.settings.fontdict)
146
154
 
147
- self.fig.set_size_inches(*self.settings.figsize)
148
- self.fig.subplots_adjust(**self.settings.subplots_adjust)
149
- self.fig.set_dpi(self.get_setting("dpi", 100))
155
+ figw.fig.set_size_inches(*figw.settings.figsize)
156
+ figw.fig.subplots_adjust(**figw.settings.subplots_adjust)
157
+ figw.fig.set_dpi(figw.get_setting("dpi", 100))
150
158
 
151
- for ax in self.axes:
159
+ for ax in figw.axes:
152
160
  ax.exit()
153
161
  if not ax.ax.has_data():
154
- self.fig.delaxes(ax.ax)
162
+ figw.fig.delaxes(ax.ax)
155
163
 
156
164
  plt.show()
157
- plt.close(self.fig)
165
+ plt.close(figw.fig)
158
166
  plt.style.use("default")
159
167
 
160
- self.entered = False
168
+ self._entered_copy = None
161
169
 
162
170
  def __repr__(self) -> str:
163
171
  with self as fig:
@@ -191,13 +199,25 @@ class FigWrapper(PlotSettable):
191
199
  self._set(inplace=True, **kwargs)
192
200
 
193
201
  def setting_check(self, key: SettingKey, value: Any) -> None:
194
- if self.entered and key == "style":
202
+ entered = self._entered_copy is not None
203
+ if entered and key == "style":
195
204
  logging.warning(
196
205
  "setting the '%s' of a figure has no effect unless it's done "
197
206
  "before invoking context manager",
198
207
  key,
199
208
  )
200
209
 
210
+ def copy(self) -> Self:
211
+ obj = self.customize(
212
+ self.__class__,
213
+ nrows=self.nrows,
214
+ ncols=self.ncols,
215
+ active=self.active,
216
+ )
217
+ obj.artists = self.artists
218
+ obj._entered_copy = None
219
+ return obj
220
+
201
221
 
202
222
  class DoubleEnteredError(Exception):
203
223
  """Raised when entering a Figwrapper for twice."""
@@ -126,21 +126,43 @@ def data(*x: Any, label: Optional[str | list[str]] = None) -> PlotDataSet:
126
126
  if not x:
127
127
  raise ValueError("at least one dataset should be provided")
128
128
 
129
- if len(x) > 1:
129
+ expanded_data: list[Any] = []
130
+ expanded_names: list[Optional[str]] = []
131
+ inferred_names = _infer_var_names(*x)
132
+ for i, value in enumerate(x):
133
+ if isinstance(value, PlotDataSets):
134
+ expanded_data.extend(value.__multiobjects__)
135
+ expanded_names.extend([None] * len(value.__multiobjects__))
136
+ else:
137
+ expanded_data.append(value)
138
+ expanded_names.append(inferred_names[i])
139
+
140
+ normalized_data: list[np.ndarray] = []
141
+ for value in expanded_data:
142
+ if isinstance(value, PlotDataSet):
143
+ normalized_data.append(np.array(value.data))
144
+ else:
145
+ normalized_data.append(np.array(value))
146
+
147
+ if len(expanded_data) > 1:
130
148
  if label is None:
131
- label = [
132
- lb if lb is not None else f"x{i}"
133
- for i, lb in enumerate(_infer_var_names(*x), start=1)
134
- ]
149
+ label = []
150
+ for i, (d, inferred_name) in enumerate(
151
+ zip(expanded_data, expanded_names), start=1
152
+ ):
153
+ if isinstance(d, PlotDataSet):
154
+ label.append(d.formatted_label())
155
+ else:
156
+ label.append(
157
+ inferred_name if inferred_name is not None else f"x{i}"
158
+ )
135
159
  elif isinstance(label, str):
136
160
  raise ValueError(
137
161
  "for multiple datasets, please provide labels as a list of strings"
138
162
  )
139
- elif len(label) != len(x):
140
- raise ValueError(
141
- f"label should have the same length as x ({len(x)}), got {len(label)}"
142
- )
143
- datas = [PlotDataSet(np.array(d), lb) for d, lb in zip(x, label)]
163
+ elif len(label) != len(expanded_data):
164
+ raise ValueError(f"expected {len(expanded_data)} labels, got {len(label)}")
165
+ datas = [PlotDataSet(d, lb) for d, lb in zip(normalized_data, label)]
144
166
  return PlotDataSets(*datas)
145
167
 
146
168
  if isinstance(label, list):
@@ -149,8 +171,13 @@ def data(*x: Any, label: Optional[str | list[str]] = None) -> PlotDataSet:
149
171
  "the data has only one dimension"
150
172
  )
151
173
  if label is None:
152
- label = _infer_assigned_name() or _infer_var_names(x[0])[0] or "x1"
153
- return PlotDataSet(np.array(x[0]), label=label)
174
+ original_label = (
175
+ expanded_data[0].label
176
+ if isinstance(expanded_data[0], PlotDataSet)
177
+ else None
178
+ )
179
+ label = original_label or _infer_assigned_name() or expanded_names[0] or "x1"
180
+ return PlotDataSet(normalized_data[0], label=label)
154
181
 
155
182
 
156
183
  def figure(
File without changes
File without changes
File without changes
File without changes