seolpyo-mplchart 1.3.1.2__py3-none-any.whl → 1.4.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.
Potentially problematic release.
This version of seolpyo-mplchart might be problematic. Click here for more details.
- seolpyo_mplchart/__init__.py +8 -8
- seolpyo_mplchart/_cursor.py +221 -182
- seolpyo_mplchart/_draw.py +211 -235
- seolpyo_mplchart/_slider.py +146 -138
- {seolpyo_mplchart-1.3.1.2.dist-info → seolpyo_mplchart-1.4.0.1.dist-info}/METADATA +1 -1
- {seolpyo_mplchart-1.3.1.2.dist-info → seolpyo_mplchart-1.4.0.1.dist-info}/RECORD +8 -8
- {seolpyo_mplchart-1.3.1.2.dist-info → seolpyo_mplchart-1.4.0.1.dist-info}/WHEEL +1 -1
- {seolpyo_mplchart-1.3.1.2.dist-info → seolpyo_mplchart-1.4.0.1.dist-info}/top_level.txt +0 -0
seolpyo_mplchart/_slider.py
CHANGED
|
@@ -3,7 +3,6 @@ from matplotlib.axes import Axes
|
|
|
3
3
|
from matplotlib.collections import LineCollection
|
|
4
4
|
from matplotlib.text import Text
|
|
5
5
|
from matplotlib.backend_bases import MouseEvent, MouseButton, cursors
|
|
6
|
-
import pandas as pd
|
|
7
6
|
|
|
8
7
|
from ._base import convert_unit
|
|
9
8
|
from ._cursor import BaseMixin as BM, Mixin as M
|
|
@@ -90,7 +89,7 @@ class PlotMixin(BM):
|
|
|
90
89
|
|
|
91
90
|
class CollectionMixin(PlotMixin):
|
|
92
91
|
min_distance = 30
|
|
93
|
-
color_navigator_line = '#
|
|
92
|
+
color_navigator_line = '#1E78FF'
|
|
94
93
|
color_navigator_cover = 'k'
|
|
95
94
|
|
|
96
95
|
def _add_collection(self):
|
|
@@ -100,15 +99,15 @@ class CollectionMixin(PlotMixin):
|
|
|
100
99
|
self.ax_slider.add_artist(self.collection_slider)
|
|
101
100
|
|
|
102
101
|
# 슬라이더 네비게이터
|
|
103
|
-
self.
|
|
104
|
-
self.ax_slider.add_artist(self.
|
|
102
|
+
self.collection_navigator = LineCollection([], animated=True, edgecolors=[self.color_navigator_cover, self.color_navigator_line], alpha=(0.3, 1.0))
|
|
103
|
+
self.ax_slider.add_artist(self.collection_navigator)
|
|
105
104
|
|
|
106
105
|
lineKwargs = {'edgecolor': 'k', 'linewidth': 1, 'linestyle': '-'}
|
|
107
106
|
lineKwargs.update(self.lineKwargs)
|
|
108
107
|
lineKwargs.update({'segments': [], 'animated': True})
|
|
109
108
|
|
|
110
|
-
self.
|
|
111
|
-
self.ax_slider.add_artist(self.
|
|
109
|
+
self.collection_slider_vline = LineCollection(**lineKwargs)
|
|
110
|
+
self.ax_slider.add_artist(self.collection_slider_vline)
|
|
112
111
|
|
|
113
112
|
textboxKwargs = {'boxstyle': 'round', 'facecolor': 'w'}
|
|
114
113
|
textboxKwargs.update(self.textboxKwargs)
|
|
@@ -116,13 +115,17 @@ class CollectionMixin(PlotMixin):
|
|
|
116
115
|
textKwargs.update({'animated': True, 'bbox': textboxKwargs, 'horizontalalignment': '', 'verticalalignment': ''})
|
|
117
116
|
(textKwargs.pop('horizontalalignment'), textKwargs.pop('verticalalignment'))
|
|
118
117
|
|
|
119
|
-
self.
|
|
120
|
-
self.ax_slider.add_artist(self.
|
|
118
|
+
self.artist_text_slider = Text(**textKwargs, horizontalalignment='center', verticalalignment='top')
|
|
119
|
+
self.ax_slider.add_artist(self.artist_text_slider)
|
|
121
120
|
return
|
|
122
121
|
|
|
123
|
-
def
|
|
124
|
-
super().
|
|
122
|
+
def _create_segments(self):
|
|
123
|
+
super()._create_segments()
|
|
125
124
|
|
|
125
|
+
self._create_slider_segment()
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
def _create_slider_segment(self):
|
|
126
129
|
keys = []
|
|
127
130
|
for i in reversed(self.list_ma):
|
|
128
131
|
keys.append('x')
|
|
@@ -131,11 +134,13 @@ class CollectionMixin(PlotMixin):
|
|
|
131
134
|
segment_slider = self.df[keys + ['x', self.close] ].values
|
|
132
135
|
segment_slider = segment_slider.reshape(segment_slider.shape[0], len(self.list_ma)+1, 2).swapaxes(0, 1)
|
|
133
136
|
self.collection_slider.set_segments(segment_slider)
|
|
134
|
-
|
|
137
|
+
linewidth = [1 for _ in self.list_ma]
|
|
138
|
+
self.collection_slider.set_linewidth(linewidth + [2.1])
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
self._create_slider_color_segments()
|
|
141
|
+
return
|
|
138
142
|
|
|
143
|
+
def _create_slider_color_segments(self):
|
|
139
144
|
self.collection_slider.set_edgecolor(self.edgecolor_ma + [self.color_priceline])
|
|
140
145
|
return
|
|
141
146
|
|
|
@@ -143,7 +148,7 @@ class CollectionMixin(PlotMixin):
|
|
|
143
148
|
super().change_background_color(color)
|
|
144
149
|
|
|
145
150
|
self.ax_slider.set_facecolor(color)
|
|
146
|
-
self.
|
|
151
|
+
self.artist_text_slider.set_backgroundcolor(color)
|
|
147
152
|
return
|
|
148
153
|
|
|
149
154
|
def change_tick_color(self, color):
|
|
@@ -156,14 +161,14 @@ class CollectionMixin(PlotMixin):
|
|
|
156
161
|
def change_text_color(self, color):
|
|
157
162
|
super().change_text_color(color)
|
|
158
163
|
|
|
159
|
-
self.
|
|
164
|
+
self.artist_text_slider.set_color(color)
|
|
160
165
|
return
|
|
161
166
|
|
|
162
167
|
def change_line_color(self, color):
|
|
163
168
|
super().change_line_color(color)
|
|
164
169
|
|
|
165
|
-
self.
|
|
166
|
-
self.
|
|
170
|
+
self.artist_text_slider.get_bbox_patch().set_edgecolor(color)
|
|
171
|
+
self.collection_slider_vline.set_edgecolor(color)
|
|
167
172
|
return
|
|
168
173
|
|
|
169
174
|
|
|
@@ -172,7 +177,7 @@ class NavigatorMixin(CollectionMixin):
|
|
|
172
177
|
xmax = self.list_index[-1]
|
|
173
178
|
# 슬라이더 xlim
|
|
174
179
|
xdistance = xmax / 30
|
|
175
|
-
self.slider_xmin, self.slider_xmax = (-xdistance, xmax
|
|
180
|
+
self.slider_xmin, self.slider_xmax = (-xdistance, xmax+xdistance)
|
|
176
181
|
self.ax_slider.set_xlim(self.slider_xmin, self.slider_xmax)
|
|
177
182
|
|
|
178
183
|
# 슬라이더 ylim
|
|
@@ -184,9 +189,9 @@ class NavigatorMixin(CollectionMixin):
|
|
|
184
189
|
self.ax_slider.set_ylim(self.slider_ymin, self.slider_ymax)
|
|
185
190
|
|
|
186
191
|
# 슬라이더 텍스트 y
|
|
187
|
-
self.
|
|
192
|
+
self.artist_text_slider.set_y(ymax)
|
|
188
193
|
|
|
189
|
-
self.
|
|
194
|
+
self.collection_navigator.set_linewidth([ysub+ysub, 5])
|
|
190
195
|
|
|
191
196
|
# 네비게이터 라인 선택 범위
|
|
192
197
|
xsub = self.slider_xmax - self.slider_xmin
|
|
@@ -196,50 +201,51 @@ class NavigatorMixin(CollectionMixin):
|
|
|
196
201
|
return
|
|
197
202
|
|
|
198
203
|
def _set_navigator(self, navmin, navmax):
|
|
199
|
-
|
|
204
|
+
seg = [
|
|
200
205
|
(
|
|
201
206
|
(self.slider_xmin, self.sldier_ymiddle),
|
|
202
|
-
(navmin, self.sldier_ymiddle)
|
|
207
|
+
(navmin, self.sldier_ymiddle),
|
|
203
208
|
),
|
|
204
209
|
(
|
|
205
210
|
(navmin, self.slider_ymin),
|
|
206
|
-
(navmin, self.slider_ymax)
|
|
211
|
+
(navmin, self.slider_ymax),
|
|
207
212
|
),
|
|
208
213
|
(
|
|
209
214
|
(navmax, self.sldier_ymiddle),
|
|
210
|
-
(self.slider_xmax, self.sldier_ymiddle)
|
|
215
|
+
(self.slider_xmax, self.sldier_ymiddle),
|
|
211
216
|
),
|
|
212
217
|
(
|
|
213
218
|
(navmax, self.slider_ymin),
|
|
214
|
-
(navmax, self.slider_ymax)
|
|
219
|
+
(navmax, self.slider_ymax),
|
|
215
220
|
),
|
|
216
221
|
]
|
|
217
222
|
|
|
218
|
-
self.
|
|
223
|
+
self.collection_navigator.set_segments(seg)
|
|
219
224
|
return
|
|
220
225
|
|
|
221
226
|
|
|
222
227
|
class DataMixin(NavigatorMixin):
|
|
223
|
-
navcoordinate = (0, 0)
|
|
228
|
+
navcoordinate: tuple[int, int] = (0, 0)
|
|
224
229
|
|
|
225
230
|
def set_data(self, df, sort_df=True, calc_ma=True, set_candlecolor=True, set_volumecolor=True, calc_info=True, change_lim=True, *args, **kwargs):
|
|
226
231
|
self._generate_data(df, sort_df, calc_ma, set_candlecolor, set_volumecolor, calc_info, *args, **kwargs)
|
|
227
|
-
self.
|
|
228
|
-
|
|
232
|
+
self._create_segments()
|
|
233
|
+
|
|
229
234
|
vmin, vmax = self.navcoordinate
|
|
230
235
|
if change_lim or (vmax-vmin) < self.min_distance:
|
|
231
236
|
vmin, vmax = self.get_default_lim()
|
|
232
|
-
self.navcoordinate = (vmin, vmax)
|
|
237
|
+
self.navcoordinate = (vmin, vmax-1)
|
|
238
|
+
else: vmax += 1
|
|
233
239
|
|
|
234
240
|
self._set_lim(vmin, vmax)
|
|
235
241
|
self._set_slider_lim()
|
|
236
|
-
self._set_navigator(
|
|
242
|
+
self._set_navigator(*self.navcoordinate)
|
|
237
243
|
|
|
238
|
-
self._length_text = self.df[(self.volume if self.volume else self.high)].apply(lambda x: len(
|
|
244
|
+
self._length_text = self.df[(self.volume if self.volume else self.high)].apply(lambda x: len(f'{x:,}')).max()
|
|
239
245
|
return
|
|
240
246
|
|
|
241
247
|
def get_default_lim(self):
|
|
242
|
-
xmax = self.list_index[-1]
|
|
248
|
+
xmax = self.list_index[-1] + 1
|
|
243
249
|
xmin = xmax - 120
|
|
244
250
|
if xmin < 0: xmin = 0
|
|
245
251
|
return (xmin, xmax)
|
|
@@ -257,16 +263,17 @@ class BackgroundMixin(DataMixin):
|
|
|
257
263
|
self._draw_artist()
|
|
258
264
|
self.background = renderer.copy_from_bbox(self.figure.bbox)
|
|
259
265
|
|
|
260
|
-
self.
|
|
266
|
+
self.collection_navigator.draw(self.figure.canvas.renderer)
|
|
261
267
|
self.background_with_nav = renderer.copy_from_bbox(self.figure.bbox)
|
|
262
268
|
return
|
|
263
269
|
|
|
264
270
|
def _restore_region(self, is_empty=False, with_nav=True):
|
|
265
271
|
if not self.background: self._create_background()
|
|
266
272
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
273
|
+
restore_region = self.figure.canvas.renderer.restore_region
|
|
274
|
+
if is_empty: restore_region(self.background_emtpy)
|
|
275
|
+
elif with_nav: restore_region(self.background_with_nav)
|
|
276
|
+
else: restore_region(self.background)
|
|
270
277
|
return
|
|
271
278
|
|
|
272
279
|
|
|
@@ -274,19 +281,31 @@ class MouseMoveMixin(BackgroundMixin):
|
|
|
274
281
|
in_slider = False
|
|
275
282
|
is_click_slider = False
|
|
276
283
|
|
|
284
|
+
def _erase_crossline(self):
|
|
285
|
+
boolen = super()._erase_crossline()
|
|
286
|
+
if boolen: return boolen
|
|
287
|
+
|
|
288
|
+
seg = self.collection_slider_vline.get_segments()
|
|
289
|
+
if seg:
|
|
290
|
+
self.collection_slider_vline.set_segments([])
|
|
291
|
+
return True
|
|
292
|
+
return False
|
|
293
|
+
|
|
277
294
|
def _on_move(self, e):
|
|
278
295
|
self._on_move_action(e)
|
|
279
296
|
|
|
280
|
-
self._restore_region((self.is_click_slider and self.in_slider))
|
|
281
|
-
|
|
282
297
|
if self.in_slider:
|
|
298
|
+
self._restore_region(self.is_click_slider)
|
|
283
299
|
self._on_move_slider(e)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
self.
|
|
288
|
-
|
|
289
|
-
|
|
300
|
+
self.figure.canvas.blit()
|
|
301
|
+
elif self.in_price_chart or self.in_volume_chart:
|
|
302
|
+
self._restore_region()
|
|
303
|
+
self._draw_crossline(e, self.in_price_chart)
|
|
304
|
+
self.figure.canvas.blit()
|
|
305
|
+
else:
|
|
306
|
+
if self._erase_crossline():
|
|
307
|
+
self._restore_region()
|
|
308
|
+
self.figure.canvas.blit()
|
|
290
309
|
return
|
|
291
310
|
|
|
292
311
|
def _on_move_action(self, e: MouseEvent):
|
|
@@ -323,34 +342,41 @@ class MouseMoveMixin(BackgroundMixin):
|
|
|
323
342
|
if not ax or e.xdata is None or e.ydata is None:
|
|
324
343
|
self.in_slider, self.in_price_chart, self.in_volume_chart = (False, False, False)
|
|
325
344
|
else:
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
345
|
+
if ax is self.ax_slider:
|
|
346
|
+
self.in_slider = True
|
|
347
|
+
self.in_price_chart = False
|
|
348
|
+
self.in_volume_chart = False
|
|
349
|
+
elif ax is self.ax_price:
|
|
350
|
+
self.in_slider = False
|
|
351
|
+
self.in_price_chart = True
|
|
352
|
+
self.in_volume_chart = False
|
|
353
|
+
elif ax is self.ax_volume:
|
|
354
|
+
self.in_slider = False
|
|
355
|
+
self.in_price_chart = False
|
|
356
|
+
self.in_volume_chart = True
|
|
357
|
+
else:
|
|
358
|
+
self.in_slider = False
|
|
359
|
+
self.in_price_chart = False
|
|
360
|
+
self.in_volume_chart = False
|
|
329
361
|
return
|
|
330
362
|
|
|
331
363
|
def _on_move_slider(self, e: MouseEvent):
|
|
332
364
|
x = e.xdata
|
|
333
|
-
|
|
334
365
|
if self.intx is not None:
|
|
335
366
|
renderer = self.figure.canvas.renderer
|
|
336
|
-
self.
|
|
337
|
-
self.
|
|
367
|
+
self.collection_slider_vline.set_segments([((x, self.slider_ymin), (x, self.slider_ymax))])
|
|
368
|
+
self.collection_slider_vline.draw(renderer)
|
|
338
369
|
|
|
339
370
|
if self.in_slider:
|
|
340
|
-
self.
|
|
341
|
-
self.
|
|
342
|
-
self.
|
|
371
|
+
self.artist_text_slider.set_text(f'{self.df[self.date][self.intx]}')
|
|
372
|
+
self.artist_text_slider.set_x(x)
|
|
373
|
+
self.artist_text_slider.draw(renderer)
|
|
343
374
|
return
|
|
344
375
|
|
|
345
|
-
def
|
|
346
|
-
self.
|
|
347
|
-
self.
|
|
348
|
-
return super().
|
|
349
|
-
|
|
350
|
-
def _on_move_volume_chart(self, e: MouseEvent):
|
|
351
|
-
self.slider_vline.set_segments([((e.xdata, self.slider_ymin), (e.xdata, self.slider_ymax))])
|
|
352
|
-
self.slider_vline.draw(self.figure.canvas.renderer)
|
|
353
|
-
return super()._on_move_volume_chart(e)
|
|
376
|
+
def _draw_crossline(self, e: MouseEvent, in_price_chart):
|
|
377
|
+
self.collection_slider_vline.set_segments([((e.xdata, self.slider_ymin), (e.xdata, self.slider_ymax))])
|
|
378
|
+
self.collection_slider_vline.draw(self.figure.canvas.renderer)
|
|
379
|
+
return super()._draw_crossline(e, in_price_chart)
|
|
354
380
|
|
|
355
381
|
|
|
356
382
|
class ClickMixin(MouseMoveMixin):
|
|
@@ -377,14 +403,16 @@ class ClickMixin(MouseMoveMixin):
|
|
|
377
403
|
x = e.xdata.__int__()
|
|
378
404
|
navmin, navmax = self.navcoordinate
|
|
379
405
|
|
|
380
|
-
|
|
381
|
-
rightmin
|
|
406
|
+
leftmax = navmin+self._navLineWidth_half
|
|
407
|
+
rightmin = navmax-self._navLineWidth_half
|
|
382
408
|
|
|
383
409
|
grater_than_left, less_then_right = (leftmax < x, x < rightmin)
|
|
384
410
|
if grater_than_left and less_then_right:
|
|
385
411
|
self.is_move = True
|
|
386
412
|
self.x_click = x
|
|
387
413
|
else:
|
|
414
|
+
leftmin = navmin - self._navLineWidth
|
|
415
|
+
rightmax = navmax+self._navLineWidth
|
|
388
416
|
if not grater_than_left and leftmin <= x:
|
|
389
417
|
self.click_navleft = True
|
|
390
418
|
self.x_click = navmax
|
|
@@ -404,9 +432,9 @@ class SliderSelectMixin(ClickMixin):
|
|
|
404
432
|
return super()._on_move_slider(e)
|
|
405
433
|
|
|
406
434
|
def _set_navcoordinate(self, e: MouseEvent):
|
|
407
|
-
x = e.xdata.__int__()
|
|
408
435
|
navmin, navmax = self.navcoordinate
|
|
409
436
|
|
|
437
|
+
x = e.xdata.__int__()
|
|
410
438
|
if self.is_move:
|
|
411
439
|
xsub = self.x_click - x
|
|
412
440
|
navmin, navmax = (navmin-xsub, navmax-xsub)
|
|
@@ -418,32 +446,32 @@ class SliderSelectMixin(ClickMixin):
|
|
|
418
446
|
self.navcoordinate = (navmin, navmax)
|
|
419
447
|
self.x_click = x
|
|
420
448
|
|
|
421
|
-
self._set_lim(navmin, navmax, simpler=True, set_ma=(navmax-navmin < self.limit_ma))
|
|
449
|
+
self._set_lim(navmin, navmax+1, simpler=True, set_ma=(navmax-navmin < self.limit_ma))
|
|
422
450
|
|
|
423
451
|
self._set_navigator(navmin, navmax)
|
|
424
|
-
self.
|
|
452
|
+
self.collection_navigator.draw(self.figure.canvas.renderer)
|
|
425
453
|
|
|
426
454
|
self._draw_artist()
|
|
427
455
|
self.background_with_nav = self.figure.canvas.renderer.copy_from_bbox(self.figure.bbox)
|
|
428
|
-
self._restore_region(
|
|
456
|
+
self._restore_region()
|
|
429
457
|
else:
|
|
430
458
|
navmin, navmax = (x, self.x_click) if x < self.x_click else (self.x_click, x)
|
|
431
459
|
|
|
432
460
|
# 슬라이더가 차트를 벗어나지 않도록 선택 영역 제한
|
|
433
461
|
if navmax < 0 or self.list_index[-1] < navmin:
|
|
434
|
-
seg = self.
|
|
462
|
+
seg = self.collection_navigator.get_segments()
|
|
435
463
|
navmin, navmax = (int(seg[1][0][0]), int(seg[3][0][0]))
|
|
436
464
|
|
|
437
465
|
nsub = navmax - navmin
|
|
438
466
|
if nsub < self.min_distance:
|
|
439
467
|
self._restore_region(False, False)
|
|
440
468
|
self._set_navigator(navmin, navmax)
|
|
441
|
-
self.
|
|
469
|
+
self.collection_navigator.draw(self.figure.canvas.renderer)
|
|
442
470
|
else:
|
|
443
|
-
self._set_lim(navmin, navmax, simpler=True, set_ma=(nsub < self.limit_ma))
|
|
471
|
+
self._set_lim(navmin, navmax+1, simpler=True, set_ma=(nsub < self.limit_ma))
|
|
444
472
|
self._set_navigator(navmin, navmax)
|
|
445
473
|
|
|
446
|
-
self.
|
|
474
|
+
self.collection_navigator.draw(self.figure.canvas.renderer)
|
|
447
475
|
|
|
448
476
|
self._draw_artist()
|
|
449
477
|
self.background_with_nav = self.figure.canvas.renderer.copy_from_bbox(self.figure.bbox)
|
|
@@ -464,23 +492,23 @@ class ReleaseMixin(SliderSelectMixin):
|
|
|
464
492
|
|
|
465
493
|
def _on_release_slider(self, e: MouseEvent):
|
|
466
494
|
if not self.is_move:
|
|
467
|
-
seg = self.
|
|
495
|
+
seg = self.collection_navigator.get_segments()
|
|
468
496
|
navmin, navmax = (int(seg[1][0][0]), int(seg[3][0][0]))
|
|
469
497
|
nsub = navmax - navmin
|
|
470
498
|
if self.min_distance <= nsub: self.navcoordinate = (navmin, navmax)
|
|
471
499
|
else:
|
|
472
500
|
self.background_with_nav = self.background_with_nav_pre
|
|
473
501
|
navmin, navmax = self.navcoordinate
|
|
474
|
-
self._set_lim(navmin, navmax, simpler=True, set_ma=(nsub < self.limit_ma))
|
|
502
|
+
self._set_lim(navmin, navmax+1, simpler=True, set_ma=(nsub < self.limit_ma))
|
|
475
503
|
self._restore_region(False, True)
|
|
476
|
-
self.
|
|
504
|
+
self.figure.canvas.blit()
|
|
477
505
|
self._set_navigator(*self.navcoordinate)
|
|
478
506
|
|
|
479
507
|
self.is_click_slider = False
|
|
480
508
|
self.is_move = False
|
|
481
509
|
self.click_navleft, self.click_navright = (False, False)
|
|
482
510
|
|
|
483
|
-
self.
|
|
511
|
+
self.figure.canvas.draw()
|
|
484
512
|
return
|
|
485
513
|
|
|
486
514
|
|
|
@@ -488,23 +516,30 @@ class ChartClickMixin(ReleaseMixin):
|
|
|
488
516
|
is_click_chart = False
|
|
489
517
|
|
|
490
518
|
def _on_click(self, e: MouseEvent):
|
|
491
|
-
if
|
|
492
|
-
(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
519
|
+
if e.button == MouseButton.LEFT:
|
|
520
|
+
if (
|
|
521
|
+
not self.is_click_chart
|
|
522
|
+
and (self.in_price_chart or self.in_volume_chart)
|
|
523
|
+
): self._on_click_chart(e)
|
|
524
|
+
elif not self.is_click_slider and self.in_slider:
|
|
525
|
+
self._on_click_slider(e)
|
|
497
526
|
return
|
|
498
527
|
|
|
499
528
|
def _on_click_chart(self, e: MouseEvent):
|
|
500
529
|
self.is_click_chart = True
|
|
501
|
-
|
|
530
|
+
x = e.xdata.__int__()
|
|
531
|
+
self.x_click = x - self.navcoordinate[0]
|
|
502
532
|
self.figure.canvas.set_cursor(cursors.RESIZE_HORIZONTAL)
|
|
503
533
|
return
|
|
504
534
|
|
|
505
535
|
def _on_release(self, e):
|
|
506
|
-
if
|
|
507
|
-
|
|
536
|
+
if e.button == MouseButton.LEFT:
|
|
537
|
+
if (
|
|
538
|
+
self.is_click_chart
|
|
539
|
+
and (self.in_price_chart or self.in_volume_chart)
|
|
540
|
+
): self._on_release_chart(e)
|
|
541
|
+
elif self.is_click_slider and self.in_slider:
|
|
542
|
+
self._on_release_slider(e)
|
|
508
543
|
return
|
|
509
544
|
|
|
510
545
|
def _on_release_chart(self, e):
|
|
@@ -519,50 +554,42 @@ class ChartClickMixin(ReleaseMixin):
|
|
|
519
554
|
def _on_move(self, e):
|
|
520
555
|
self._on_move_action(e)
|
|
521
556
|
|
|
522
|
-
need_slider_action = self.is_click_slider and self.in_slider
|
|
523
|
-
need_chart_action = False if need_slider_action else self.is_click_chart and (self.in_price_chart or self.in_volume_chart)
|
|
524
|
-
self._restore_region((need_slider_action or need_chart_action))
|
|
525
|
-
|
|
526
557
|
if self.in_slider:
|
|
558
|
+
self._restore_region(self.is_click_slider)
|
|
527
559
|
self._on_move_slider(e)
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
self.
|
|
532
|
-
|
|
533
|
-
|
|
560
|
+
self.figure.canvas.blit()
|
|
561
|
+
elif self.in_price_chart or self.in_volume_chart:
|
|
562
|
+
self._restore_region(self.is_click_chart)
|
|
563
|
+
if not self.is_click_chart:
|
|
564
|
+
self._draw_crossline(e, self.in_price_chart)
|
|
565
|
+
else: self._move_chart(e)
|
|
566
|
+
self.figure.canvas.blit()
|
|
567
|
+
else:
|
|
568
|
+
if self._erase_crossline():
|
|
569
|
+
self._restore_region()
|
|
570
|
+
self.figure.canvas.blit()
|
|
534
571
|
return
|
|
535
572
|
|
|
536
|
-
def _on_move_price_chart(self, e):
|
|
537
|
-
if self.is_click_chart: self._move_chart(e)
|
|
538
|
-
return super()._on_move_price_chart(e)
|
|
539
|
-
|
|
540
|
-
def _on_move_volume_chart(self, e):
|
|
541
|
-
if self.is_click_chart: self._move_chart(e)
|
|
542
|
-
return super()._on_move_volume_chart(e)
|
|
543
|
-
|
|
544
573
|
def _move_chart(self, e: MouseEvent):
|
|
545
|
-
x = e.x
|
|
546
574
|
left, right = self.navcoordinate
|
|
547
|
-
|
|
548
|
-
xsub = x - self.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
self.navigator.draw(self.figure.canvas.renderer)
|
|
575
|
+
x = e.xdata.__int__() - left
|
|
576
|
+
xsub = x - self.x_click
|
|
577
|
+
if not xsub:
|
|
578
|
+
self.collection_navigator.draw(self.figure.canvas.renderer)
|
|
552
579
|
self._draw_artist()
|
|
553
580
|
else:
|
|
554
|
-
left, right = (left-
|
|
555
|
-
if right < 0 or self.df.index[-1] < left: self._restore_region(
|
|
581
|
+
left, right = (left-xsub, right-xsub)
|
|
582
|
+
if right < 0 or self.df.index[-1] < left: self._restore_region()
|
|
556
583
|
else:
|
|
584
|
+
self.x_click = x
|
|
557
585
|
self.navcoordinate = (left, right)
|
|
558
|
-
self._set_lim(left, right, simpler=True, set_ma=((right-left) < self.limit_ma))
|
|
586
|
+
self._set_lim(left, right+1, simpler=True, set_ma=((right-left) < self.limit_ma))
|
|
559
587
|
self._set_navigator(left, right)
|
|
560
|
-
self.
|
|
588
|
+
self.collection_navigator.draw(self.figure.canvas.renderer)
|
|
561
589
|
|
|
562
590
|
self._draw_artist()
|
|
563
591
|
self.background_with_nav = self.figure.canvas.renderer.copy_from_bbox(self.figure.bbox)
|
|
564
|
-
self._restore_region(
|
|
565
|
-
self._x_click = x
|
|
592
|
+
self._restore_region()
|
|
566
593
|
return
|
|
567
594
|
|
|
568
595
|
|
|
@@ -571,17 +598,13 @@ class BaseMixin(ChartClickMixin):
|
|
|
571
598
|
|
|
572
599
|
|
|
573
600
|
class Chart(BaseMixin, Mixin):
|
|
574
|
-
def _add_collection(self):
|
|
575
|
-
super()._add_collection()
|
|
576
|
-
return self.add_artist()
|
|
577
|
-
|
|
578
601
|
def _draw_artist(self):
|
|
579
602
|
super()._draw_artist()
|
|
580
603
|
return self.draw_artist()
|
|
581
604
|
|
|
582
|
-
def
|
|
583
|
-
|
|
584
|
-
return
|
|
605
|
+
def _set_lim(self, xmin, xmax, simpler=False, set_ma=True):
|
|
606
|
+
super()._set_lim(xmin, xmax, simpler, set_ma)
|
|
607
|
+
return self.on_change_xlim(xmin, xmax, simpler, set_ma)
|
|
585
608
|
|
|
586
609
|
def _on_draw(self, e):
|
|
587
610
|
super()._on_draw(e)
|
|
@@ -591,21 +614,6 @@ class Chart(BaseMixin, Mixin):
|
|
|
591
614
|
self.on_pick(e)
|
|
592
615
|
return super()._on_pick(e)
|
|
593
616
|
|
|
594
|
-
def _set_candle_segments(self, index_start, index_end):
|
|
595
|
-
super()._set_candle_segments(index_start, index_end)
|
|
596
|
-
self.set_segment(index_start, index_end)
|
|
597
|
-
return
|
|
598
|
-
|
|
599
|
-
def _set_wick_segments(self, index_start, index_end, simpler=False):
|
|
600
|
-
super()._set_wick_segments(index_start, index_end, simpler)
|
|
601
|
-
self.set_segment(index_start, index_end, simpler)
|
|
602
|
-
return
|
|
603
|
-
|
|
604
|
-
def _set_line_segments(self, index_start, index_end, simpler=False, set_ma=True):
|
|
605
|
-
super()._set_line_segments(index_start, index_end, simpler, set_ma)
|
|
606
|
-
self.set_segment(index_start, index_end, simpler, set_ma)
|
|
607
|
-
return
|
|
608
|
-
|
|
609
617
|
def _on_move(self, e):
|
|
610
618
|
super()._on_move(e)
|
|
611
619
|
return self.on_move(e)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: seolpyo-mplchart
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0.1
|
|
4
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
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
seolpyo_mplchart/__init__.py,sha256=
|
|
1
|
+
seolpyo_mplchart/__init__.py,sha256=1rY6PP1OMMr1d_5x7dlAD2ImQAXChT5spvB45j6yDp8,18255
|
|
2
2
|
seolpyo_mplchart/_base.py,sha256=3iG4AVwHR_h3rh6c1oJahWt7NvBpBFrS0bUZd4PaHfY,3921
|
|
3
|
-
seolpyo_mplchart/_cursor.py,sha256=
|
|
4
|
-
seolpyo_mplchart/_draw.py,sha256=
|
|
5
|
-
seolpyo_mplchart/_slider.py,sha256=
|
|
3
|
+
seolpyo_mplchart/_cursor.py,sha256=BXeZNRec_cUrFtBfSGMzbZM0V00Y4S23iZbK64gJR-Y,22488
|
|
4
|
+
seolpyo_mplchart/_draw.py,sha256=TGPo80yJocmXbWoCfzYKlWK6ntBElvb9IR8O54A2X5w,21174
|
|
5
|
+
seolpyo_mplchart/_slider.py,sha256=W6YGzm9dJ81YnwxDeu5QBqYWV9ec5pRmS9hyTWQ8R0c,23395
|
|
6
6
|
seolpyo_mplchart/base.py,sha256=0qdImsIMPzTTkkHzPv479BVe_ojrn45FidGE46eT5x4,3797
|
|
7
7
|
seolpyo_mplchart/cursor.py,sha256=qq1WJJa7vCE5C2XeGBECt2XqxR_WxfybZZ5u6zVx5Ps,20415
|
|
8
8
|
seolpyo_mplchart/draw.py,sha256=MiqDhbMJOSlWD6qdAghsyrZwCixcwm4nfmiinvwtt-o,21520
|
|
@@ -11,7 +11,7 @@ seolpyo_mplchart/test.py,sha256=TFnIXphJsl-B7iIhBh7-PZKUz2Gjh7mwNwrk8aUS4SA,180
|
|
|
11
11
|
seolpyo_mplchart/utils.py,sha256=a3XycRBTndrsjBw_1VKTxbSvOGpVYXHRK87v7azgRe8,1433
|
|
12
12
|
seolpyo_mplchart/data/apple.txt,sha256=0izAfweu1lLsC0IwVthdVlo9reG8KGbKGTSX5knI5Zc,1380864
|
|
13
13
|
seolpyo_mplchart/data/samsung.txt,sha256=UejaSkbzr4E5K3lkelCT0yJiWUPfmViBEaTyoXyphIs,2476424
|
|
14
|
-
seolpyo_mplchart-1.
|
|
15
|
-
seolpyo_mplchart-1.
|
|
16
|
-
seolpyo_mplchart-1.
|
|
17
|
-
seolpyo_mplchart-1.
|
|
14
|
+
seolpyo_mplchart-1.4.0.1.dist-info/METADATA,sha256=KXRagKJTEqdZ5aGtxFYjQ7j-tdYJvDCOZeTS4aO3crE,2484
|
|
15
|
+
seolpyo_mplchart-1.4.0.1.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
16
|
+
seolpyo_mplchart-1.4.0.1.dist-info/top_level.txt,sha256=KgqFn7rKWize7OjMaTCHxKm9ie6vqnyb5c8fN7y_tSo,17
|
|
17
|
+
seolpyo_mplchart-1.4.0.1.dist-info/RECORD,,
|
|
File without changes
|