seolpyo-mplchart 0.0.41__tar.gz → 0.0.61__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.

Potentially problematic release.


This version of seolpyo-mplchart might be problematic. Click here for more details.

Files changed (19) hide show
  1. {seolpyo_mplchart-0.0.41/seolpyo_mplchart.egg-info → seolpyo_mplchart-0.0.61}/PKG-INFO +2 -2
  2. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/pyproject.toml +2 -2
  3. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/cursor.py +36 -28
  4. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/slider.py +46 -48
  5. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61/seolpyo_mplchart.egg-info}/PKG-INFO +2 -2
  6. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/MANIFEST.in +0 -0
  7. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/README.md +0 -0
  8. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/__init__.py +0 -0
  9. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/base.py +0 -0
  10. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/data/apple.txt +0 -0
  11. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/data/samsung.txt +0 -0
  12. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/draw.py +0 -0
  13. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/test.py +0 -0
  14. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart/utils.py +0 -0
  15. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart.egg-info/SOURCES.txt +0 -0
  16. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart.egg-info/dependency_links.txt +0 -0
  17. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart.egg-info/requires.txt +0 -0
  18. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/seolpyo_mplchart.egg-info/top_level.txt +0 -0
  19. {seolpyo_mplchart-0.0.41 → seolpyo_mplchart-0.0.61}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: seolpyo-mplchart
3
- Version: 0.0.41
4
- Summary: Fast candlestick chart using Python.
3
+ Version: 0.0.61
4
+ Summary: Fast candlestick chart using Python. Includes navigator, slider, navigation, and text information display functions
5
5
  Author-email: white-seolpyo <white-seolpyo@naver.com>
6
6
  License: MIT License
7
7
  Project-URL: Homepage, https://white.seolpyo.com/
@@ -8,13 +8,13 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "seolpyo-mplchart"
11
- version = "0.0.41"
11
+ version = "0.0.61"
12
12
  dependencies = [
13
13
  "matplotlib >= 3.7.0",
14
14
  "pandas >= 2.0.0",
15
15
  ]
16
16
  license = {text = "MIT License"}
17
- description = "Fast candlestick chart using Python.\nIncludes navigator, slider, navigation, and text information display functions"
17
+ description = "Fast candlestick chart using Python. Includes navigator, slider, navigation, and text information display functions"
18
18
  readme = "README.md"
19
19
  requires-python = ">= 3.11"
20
20
  authors = [
@@ -79,6 +79,34 @@ class DataMixin(CollectionMixin):
79
79
  df['rate_volume'] = ((df[self.volume] - df[self.volume].shift(1)) / df[self.volume].shift(1) * 100).__round__(2).fillna(0)
80
80
  return
81
81
 
82
+ def set_text_coordante(self, vmin, vmax, pmin, pmax, volmax):
83
+ # 주가, 거래량 텍스트 x 위치
84
+ x_distance = (vmax - vmin) / 30
85
+ self.v0, self.v1 = (vmin + x_distance, vmax - x_distance)
86
+ self.text_price.set_x(self.v0)
87
+ self.text_volume.set_x(self.v0)
88
+
89
+ self.vmin, self.vmax = (vmin, vmax)
90
+ self.vmiddle = vmax - int((vmax - vmin) / 2)
91
+
92
+ psub = pmax - pmin
93
+ self.min_psub = psub / 12
94
+
95
+ # 주가 날짜 텍스트 y 위치
96
+ y = (psub) / 20 + pmin
97
+ self.text_date_price.set_y(y)
98
+ # 주가 정보 y 위치
99
+ y = pmax - (psub) / 20
100
+ self.text_price_info.set_y(y)
101
+
102
+ # 거래량 날짜 텍스트 y 위치
103
+ y = volmax * 0.85
104
+ self.text_date_volume.set_y(y)
105
+ # 거래량 정보 y 위치
106
+ self.text_volume_info.set_y(y)
107
+
108
+ return
109
+
82
110
 
83
111
  class LineMixin(DataMixin):
84
112
  in_slider, in_price, in_volume = (False, False, False)
@@ -172,8 +200,12 @@ class LineMixin(DataMixin):
172
200
  if self.in_index:
173
201
  intx = self.intx
174
202
 
175
- high = self.df[self.high][intx] * 1.02
176
- low = self.df[self.low][intx] * 0.98
203
+ h = self.df[self.high][intx]
204
+ l = self.df[self.low][intx]
205
+ sub = (h - l) / 2
206
+ if sub < self.min_psub: sub = self.min_psub
207
+ high = h + sub
208
+ low = l - sub
177
209
  if high < y or y < low: self._in_candle = False
178
210
  else:
179
211
  self._in_candle = True
@@ -227,31 +259,6 @@ class InfoMixin(LineMixin):
227
259
 
228
260
  return
229
261
 
230
- def set_text_coordante(self, vmin, vmax, pmin, pmax, volmax):
231
- # 주가, 거래량 텍스트 x 위치
232
- x_distance = (vmax - vmin) / 30
233
- self.v0, self.v1 = (vmin + x_distance, vmax - x_distance)
234
- self.text_price.set_x(self.v0)
235
- self.text_volume.set_x(self.v0)
236
-
237
- self.vmin, self.vmax = (vmin, vmax)
238
- self.vmiddle = vmax - int((vmax - vmin) / 2)
239
-
240
- # 주가 날짜 텍스트 y 위치
241
- y = (pmax - pmin) / 20 + pmin
242
- self.text_date_price.set_y(y)
243
- # 주가 정보 y 위치
244
- y = pmax - (pmax - pmin) / 20
245
- self.text_price_info.set_y(y)
246
-
247
- # 거래량 날짜 텍스트 y 위치
248
- y = volmax * 0.85
249
- self.text_date_volume.set_y(y)
250
- # 거래량 정보 y 위치
251
- self.text_volume_info.set_y(y)
252
-
253
- return
254
-
255
262
  def _slider_move_action(self, e):
256
263
  super()._slider_move_action(e)
257
264
 
@@ -424,7 +431,8 @@ if __name__ == '__main__':
424
431
  file = Path(__file__).parent / 'data/apple.txt'
425
432
  with open(file, 'r', encoding='utf-8') as txt:
426
433
  data = json.load(txt)
427
- data = data[:100]
434
+ n = 2600
435
+ data = data[n:n+100]
428
436
  df = pd.DataFrame(data)
429
437
 
430
438
  t = time()
@@ -96,9 +96,6 @@ class NavgatorMixin(Mixin):
96
96
 
97
97
  if self._navcoordinate[0] == self._navcoordinate[1]:
98
98
  self._navcoordinate = (self._navcoordinate[0], self._navcoordinate[1]+self.min_distance)
99
-
100
- self.background = None
101
- self._draw()
102
99
  return
103
100
 
104
101
 
@@ -108,19 +105,27 @@ class BackgroundMixin(NavgatorMixin):
108
105
  self._restore_region()
109
106
  return
110
107
 
111
- def _restore_region(self, with_nav=True):
108
+ def _restore_region(self, with_nav=True, empty=False, empty_with_nav=False):
112
109
  if not self.background: self._create_background()
113
110
 
114
- if with_nav: self.canvas.restore_region(self.background_with_nav)
111
+ if empty: self.canvas.restore_region(self.background_empty)
112
+ elif empty_with_nav: self.canvas.restore_region(self.background_empty_with_nav)
113
+ elif with_nav: self.canvas.restore_region(self.background_with_nav)
115
114
  else: self.canvas.renderer.restore_region(self.background)
116
115
  return
117
116
 
118
117
  def _copy_bbox(self):
119
- self.ax_slider.xaxis.draw(self.canvas.renderer)
120
- self.ax_slider.yaxis.draw(self.canvas.renderer)
121
- self.slidercollection.draw(self.canvas.renderer)
118
+ renderer = self.canvas.renderer
122
119
 
123
- super()._copy_bbox()
120
+ self.background_empty = renderer.copy_from_bbox(self.fig.bbox)
121
+
122
+ self.ax_slider.xaxis.draw(renderer)
123
+ self.ax_slider.yaxis.draw(renderer)
124
+ self.slidercollection.draw(renderer)
125
+ self.background_empty_with_nav = self.canvas.renderer.copy_from_bbox(self.fig.bbox)
126
+
127
+ self._draw_artist()
128
+ self.background = self.canvas.renderer.copy_from_bbox(self.fig.bbox)
124
129
 
125
130
  self.navigator.draw(self.canvas.renderer)
126
131
  self.background_with_nav = self.canvas.renderer.copy_from_bbox(self.fig.bbox)
@@ -158,15 +163,14 @@ class DrawMixin(BackgroundMixin):
158
163
  return
159
164
 
160
165
  def _on_release(self, e: MouseEvent):
161
- if e.inaxes is not self.ax_slider: return
162
- self.is_click, self.is_move = (False, False)
163
-
164
- if self._navcoordinate[0] == self._navcoordinate[1]:
165
- self._navcoordinate = (self._navcoordinate[0], self._navcoordinate[1]+self.min_distance)
166
+ super()._on_release(e)
166
167
  self._set_navigator(*self._navcoordinate)
167
168
 
168
- self.background = None
169
- self._draw()
169
+ self._restore_region(empty=True)
170
+ self._creating_background = False
171
+ self._create_background()
172
+ self._restore_region()
173
+ self._blit()
170
174
  return
171
175
 
172
176
  def _on_move(self, e: MouseEvent):
@@ -238,27 +242,6 @@ class DrawMixin(BackgroundMixin):
238
242
 
239
243
 
240
244
  class LimMixin(DrawMixin):
241
- def _restore_region(self, with_nav=True, empty=False):
242
- if not self.background: self._create_background()
243
-
244
- if empty: self.canvas.restore_region(self.background_empty)
245
- elif with_nav: self.canvas.restore_region(self.background_with_nav)
246
- else: self.canvas.renderer.restore_region(self.background)
247
- return
248
-
249
- def _copy_bbox(self):
250
- self.ax_slider.xaxis.draw(self.canvas.renderer)
251
- self.ax_slider.yaxis.draw(self.canvas.renderer)
252
- self.slidercollection.draw(self.canvas.renderer)
253
- self.background_empty = self.canvas.renderer.copy_from_bbox(self.fig.bbox)
254
-
255
- self._draw_artist()
256
- self.background = self.canvas.renderer.copy_from_bbox(self.fig.bbox)
257
-
258
- self.navigator.draw(self.canvas.renderer)
259
- self.background_with_nav = self.canvas.renderer.copy_from_bbox(self.fig.bbox)
260
- return
261
-
262
245
  def _on_release(self, e: MouseEvent):
263
246
  if e.inaxes is not self.ax_slider: return
264
247
  self.is_click, self.is_move = (False, False)
@@ -268,12 +251,14 @@ class LimMixin(DrawMixin):
268
251
  self._set_navigator(*self._navcoordinate)
269
252
  self._lim()
270
253
 
271
- self.background = None
272
- self._draw()
254
+ self._restore_region(empty=True)
255
+ self._creating_background = False
256
+ self._create_background()
257
+ self._blit()
273
258
  return
274
259
 
275
260
  def _on_move(self, e):
276
- self._restore_region(with_nav=(not self.is_click), empty=self.is_click)
261
+ self._restore_region(with_nav=(not self.is_click), empty_with_nav=self.is_click)
277
262
 
278
263
  self._on_move_action(e)
279
264
 
@@ -329,7 +314,7 @@ class LimMixin(DrawMixin):
329
314
 
330
315
  class SimpleMixin(LimMixin):
331
316
  simpler = False
332
- limit_volume = 2_000
317
+ limit_volume = 1_500
333
318
 
334
319
  def __init__(self, *args, **kwargs):
335
320
  super().__init__(*args, **kwargs)
@@ -351,7 +336,7 @@ class SimpleMixin(LimMixin):
351
336
  seg = self.df[['x', self.high, self.low]].agg(get_wickline, axis=1)
352
337
  self.blitcandle.set_segments(seg)
353
338
  self.blitcandle.set_edgecolor(self.df['edgecolor'])
354
- self.priceline.set_verts([self.df[['x', self.close]].apply(tuple, axis=1).tolist()])
339
+ self.priceline.set_verts(pd.array([self.df[['x', self.close]].apply(tuple, axis=1).to_list()]))
355
340
 
356
341
  volmax = self.df[self.volume].max()
357
342
  l = self.df.__len__()
@@ -381,12 +366,20 @@ class SimpleMixin(LimMixin):
381
366
  self.ax_price.xaxis.draw(renderer)
382
367
  self.ax_price.yaxis.draw(renderer)
383
368
 
384
- if self.simpler: self.blitcandle.draw(renderer)
369
+ left, right = self._navcoordinate
370
+ Range = right - left
371
+ if self.simpler:
372
+ if Range < 1_000: self.blitcandle.draw(renderer)
373
+ else: self.priceline.draw(renderer)
385
374
  elif self.candle_on_ma:
386
375
  self.macollection.draw(renderer)
387
- self.candlecollection.draw(renderer)
376
+ if 2_500 < Range: self.priceline.draw(renderer)
377
+ elif 800 < Range or 9_999 < self.xmax: self.blitcandle.draw(renderer)
378
+ else: self.candlecollection.draw(renderer)
388
379
  else:
389
- self.candlecollection.draw(renderer)
380
+ if 2_500 < Range: self.priceline.draw(renderer)
381
+ elif 800 < Range or 9_999 < self.xmax: self.blitcandle.draw(renderer)
382
+ else: self.candlecollection.draw(renderer)
390
383
  self.macollection.draw(renderer)
391
384
 
392
385
  self.ax_volume.xaxis.draw(renderer)
@@ -436,12 +429,16 @@ class ClickMixin(SimpleMixin):
436
429
  if not self.is_click: return
437
430
  elif e.inaxes is self.ax_slider: return super()._on_release(e)
438
431
  elif not self.in_price and not self.in_volume and not self.is_click_chart: return
432
+ # 차트 click release action
439
433
  self.canvas.set_cursor(cursors.POINTER)
440
434
  self.is_click, self.is_move = (False, False)
441
435
  self.is_click_chart = False
442
436
 
443
- self._draw()
444
- return self._restore_region()
437
+ self._restore_region(empty=True)
438
+ self._creating_background = False
439
+ self._create_background()
440
+ self._blit()
441
+ return
445
442
 
446
443
  def _on_chart_click(self, e: MouseEvent):
447
444
  self.is_click = True
@@ -469,7 +466,7 @@ class ClickMixin(SimpleMixin):
469
466
  return
470
467
 
471
468
  def _on_move(self, e):
472
- self._restore_region(with_nav=(not self.is_click), empty=self.is_click)
469
+ self._restore_region(with_nav=(not self.is_click), empty_with_nav=self.is_click)
473
470
 
474
471
  self._on_move_action(e)
475
472
 
@@ -594,6 +591,7 @@ if __name__ == '__main__':
594
591
  df = pd.DataFrame(data)
595
592
 
596
593
  t = time()
594
+ # c = SimpleMixin()
597
595
  c = SliderMixin()
598
596
  c.set_data(df)
599
597
  t2 = time() - t
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: seolpyo-mplchart
3
- Version: 0.0.41
4
- Summary: Fast candlestick chart using Python.
3
+ Version: 0.0.61
4
+ Summary: Fast candlestick chart using Python. Includes navigator, slider, navigation, and text information display functions
5
5
  Author-email: white-seolpyo <white-seolpyo@naver.com>
6
6
  License: MIT License
7
7
  Project-URL: Homepage, https://white.seolpyo.com/