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.

@@ -297,19 +297,19 @@ def set_theme(chart: SliderChart|CursorChart|OnlyChart, theme: Literal['light',
297
297
  chart.color_volume_up, chart.color_volume_down = ('#32CD32', '#FF4500')
298
298
  chart.color_volume_flat = 'w'
299
299
 
300
- chart.list_macolor = ('#FFFF00', '#7FFF00', '#00FFFF', '#FFA07A', '#FF00FF')
300
+ chart.list_macolor = ('#1E90FF', '#FFA500', '#FF1493', '#FFFF00', '#00CED1')
301
301
 
302
302
  chart.lineKwargs = {'edgecolor': 'w'}
303
303
  chart.color_box = 'w'
304
304
  chart.textboxKwargs = {'facecolor': 'k', 'edgecolor': 'w'}
305
305
  chart.textKwargs = {'color': 'w'}
306
- chart.color_navigator_cover, chart.color_navigator_line = ('w', '#FF2400')
306
+ chart.color_navigator_cover, chart.color_navigator_line = ('k', '#FF2400')
307
307
 
308
308
  if initialized:
309
309
  chart.change_background_color('k')
310
310
  chart.change_tick_color('w')
311
311
  chart.change_line_color('w')
312
- if hasattr(chart, 'navigator'): chart.navigator.set_edgecolor([chart.color_navigator_cover, chart.color_navigator_line])
312
+ if hasattr(chart, 'navigator'): chart.collection_navigator.set_edgecolor([chart.color_navigator_cover, chart.color_navigator_line])
313
313
 
314
314
  if hasattr(chart, 'df'):
315
315
  chart.set_data(chart.df, sort_df=False, calc_ma=False, set_candlecolor=True, set_volumecolor=True, calc_info=False, change_lim=False)
@@ -324,22 +324,22 @@ def set_theme(chart: SliderChart|CursorChart|OnlyChart, theme: Literal['light',
324
324
  chart.color_flat = 'k'
325
325
  chart.color_up_down, chart.color_down_up = ('w', 'w')
326
326
 
327
- chart.color_volume_up, chart.color_volume_down = ('#FF4D4D', '#5CA8F4')
328
- chart.color_volume_flat = '#A9A9A9'
327
+ chart.color_volume_up, chart.color_volume_down = ('#FF6666', '#5CA8F4')
328
+ chart.color_volume_flat = '#808080'
329
329
 
330
- chart.list_macolor = ('#B22222', '#228B22', '#1E90FF', '#FF8C00', '#4B0082')
330
+ chart.list_macolor = ('#006400', '#8B008B', '#FFA500', '#0000FF', '#FF0000')
331
331
 
332
332
  chart.lineKwargs = {'edgecolor': 'k'}
333
333
  chart.color_box = 'k'
334
334
  chart.textboxKwargs = {'facecolor': 'w', 'edgecolor': 'k'}
335
335
  chart.textKwargs = {'color': 'k'}
336
- chart.color_navigator_cover, chart.color_navigator_line = ('k', '#1e78ff')
336
+ chart.color_navigator_cover, chart.color_navigator_line = ('k', '#1E78FF')
337
337
 
338
338
  if initialized:
339
339
  chart.change_background_color('#fafafa')
340
340
  chart.change_tick_color('k')
341
341
  chart.change_line_color('k')
342
- if hasattr(chart, 'navigator'): chart.navigator.set_edgecolor([chart.color_navigator_cover, chart.color_navigator_line])
342
+ if hasattr(chart, 'navigator'): chart.collection_navigator.set_edgecolor([chart.color_navigator_cover, chart.color_navigator_line])
343
343
 
344
344
  if hasattr(chart, 'df'):
345
345
  chart.set_data(chart.df, sort_df=False, calc_ma=False, set_candlecolor=True, set_volumecolor=True, calc_info=False, change_lim=False)
@@ -1,6 +1,5 @@
1
1
  from fractions import Fraction
2
2
 
3
- import matplotlib.pyplot as plt
4
3
  from matplotlib.backend_bases import MouseEvent
5
4
  from matplotlib.collections import LineCollection
6
5
  from matplotlib.text import Text
@@ -34,72 +33,72 @@ class CollectionMixin(BM):
34
33
  textKwargs.update({'animated': True, 'bbox': textboxKwargs, 'horizontalalignment': '', 'verticalalignment': ''})
35
34
  (textKwargs.pop('horizontalalignment'), textKwargs.pop('verticalalignment'))
36
35
 
37
- self.price_crossline = LineCollection(**lineKwargs)
38
- self.ax_price.add_artist(self.price_crossline)
39
- self.text_date_price = Text(**textKwargs, horizontalalignment='center', verticalalignment='bottom')
40
- self.ax_price.add_artist(self.text_date_price)
41
- self.text_price = Text(**textKwargs, horizontalalignment='left', verticalalignment='center')
42
- self.ax_price.add_artist(self.text_price)
43
-
44
- self.volume_crossline = LineCollection(**lineKwargs)
45
- self.ax_volume.add_artist(self.volume_crossline)
46
- self.text_date_volume = Text(**textKwargs, horizontalalignment='center', verticalalignment='top')
47
- self.ax_volume.add_artist(self.text_date_volume)
48
- self.text_volume = Text(**textKwargs, horizontalalignment='left', verticalalignment='center')
49
- self.ax_volume.add_artist(self.text_volume)
50
-
51
- self.price_box = LineCollection([], animated=True, linewidth=1.2, edgecolor=self.color_box)
52
- self.ax_price.add_artist(self.price_box)
53
- self.text_price_info = Text(**textKwargs, horizontalalignment='left', verticalalignment='top')
54
- self.ax_price.add_artist(self.text_price_info)
55
-
56
- self.volume_box = LineCollection([], animated=True, linewidth=1.2, edgecolor=self.color_box)
57
- self.ax_volume.add_artist(self.volume_box)
58
- self.text_volume_info = Text(**textKwargs, horizontalalignment='left', verticalalignment='top')
59
- self.ax_volume.add_artist(self.text_volume_info)
36
+ self.collection_price_crossline = LineCollection(**lineKwargs)
37
+ self.ax_price.add_artist(self.collection_price_crossline)
38
+ self.artist_text_date_price = Text(**textKwargs, horizontalalignment='center', verticalalignment='bottom')
39
+ self.ax_price.add_artist(self.artist_text_date_price)
40
+ self.artist_text_price = Text(**textKwargs, horizontalalignment='left', verticalalignment='center')
41
+ self.ax_price.add_artist(self.artist_text_price)
42
+
43
+ self.collection_volume_crossline = LineCollection(**lineKwargs)
44
+ self.ax_volume.add_artist(self.collection_volume_crossline)
45
+ self.artist_text_date_volume = Text(**textKwargs, horizontalalignment='center', verticalalignment='top')
46
+ self.ax_volume.add_artist(self.artist_text_date_volume)
47
+ self.artist_text_volume = Text(**textKwargs, horizontalalignment='left', verticalalignment='center')
48
+ self.ax_volume.add_artist(self.artist_text_volume)
49
+
50
+ self.collection_price_box = LineCollection([], animated=True, linewidth=1.2, edgecolor=self.color_box)
51
+ self.ax_price.add_artist(self.collection_price_box)
52
+ self.artist_text_price_info = Text(**textKwargs, horizontalalignment='left', verticalalignment='top')
53
+ self.ax_price.add_artist(self.artist_text_price_info)
54
+
55
+ self.collection_volume_box = LineCollection([], animated=True, linewidth=1.2, edgecolor=self.color_box)
56
+ self.ax_volume.add_artist(self.collection_volume_box)
57
+ self.artist_text_volume_info = Text(**textKwargs, horizontalalignment='left', verticalalignment='top')
58
+ self.ax_volume.add_artist(self.artist_text_volume_info)
60
59
  return
61
60
 
62
61
  def change_background_color(self, color):
63
62
  super().change_background_color(color)
64
63
 
65
- self.text_price.set_backgroundcolor(color)
66
- self.text_volume.set_backgroundcolor(color)
64
+ self.artist_text_price.set_backgroundcolor(color)
65
+ self.artist_text_volume.set_backgroundcolor(color)
67
66
 
68
- self.text_date_price.set_backgroundcolor(color)
69
- self.text_date_volume.set_backgroundcolor(color)
67
+ self.artist_text_date_price.set_backgroundcolor(color)
68
+ self.artist_text_date_volume.set_backgroundcolor(color)
70
69
 
71
- self.text_price_info.set_backgroundcolor(color)
72
- self.text_volume_info.set_backgroundcolor(color)
70
+ self.artist_text_price_info.set_backgroundcolor(color)
71
+ self.artist_text_volume_info.set_backgroundcolor(color)
73
72
  return
74
73
 
75
74
  def change_text_color(self, color):
76
75
  super().change_text_color(color)
77
76
 
78
- self.text_price.set_color(color)
79
- self.text_volume.set_color(color)
77
+ self.artist_text_price.set_color(color)
78
+ self.artist_text_volume.set_color(color)
80
79
 
81
- self.text_date_price.set_color(color)
82
- self.text_date_volume.set_color(color)
80
+ self.artist_text_date_price.set_color(color)
81
+ self.artist_text_date_volume.set_color(color)
83
82
 
84
- self.text_price_info.set_color(color)
85
- self.text_volume_info.set_color(color)
83
+ self.artist_text_price_info.set_color(color)
84
+ self.artist_text_volume_info.set_color(color)
86
85
  return
87
86
 
88
87
  def change_line_color(self, color):
89
- self.price_crossline.set_edgecolor(color)
90
- self.volume_crossline.set_edgecolor(color)
88
+ self.collection_price_crossline.set_edgecolor(color)
89
+ self.collection_volume_crossline.set_edgecolor(color)
91
90
 
92
- self.price_box.set_edgecolor(color)
93
- self.volume_box.set_edgecolor(color)
91
+ self.collection_price_box.set_edgecolor(color)
92
+ self.collection_volume_box.set_edgecolor(color)
94
93
 
95
- self.text_price.get_bbox_patch().set_edgecolor(color)
96
- self.text_volume.get_bbox_patch().set_edgecolor(color)
94
+ self.artist_text_price.get_bbox_patch().set_edgecolor(color)
95
+ self.artist_text_volume.get_bbox_patch().set_edgecolor(color)
97
96
 
98
- self.text_date_price.get_bbox_patch().set_edgecolor(color)
99
- self.text_date_volume.get_bbox_patch().set_edgecolor(color)
97
+ self.artist_text_date_price.get_bbox_patch().set_edgecolor(color)
98
+ self.artist_text_date_volume.get_bbox_patch().set_edgecolor(color)
100
99
 
101
- self.text_price_info.get_bbox_patch().set_edgecolor(color)
102
- self.text_volume_info.get_bbox_patch().set_edgecolor(color)
100
+ self.artist_text_price_info.get_bbox_patch().set_edgecolor(color)
101
+ self.artist_text_volume_info.get_bbox_patch().set_edgecolor(color)
103
102
  return
104
103
 
105
104
 
@@ -121,6 +120,10 @@ class DataMixin(CollectionMixin):
121
120
  if v in _set_key: raise Exception(f'you can not set "{i}" to column key.\nself.{i}={v!r}')
122
121
  return
123
122
 
123
+ def set_data(self, df, sort_df=True, calc_ma=True, set_candlecolor=True, set_volumecolor=True, calc_info=True, *args, **kwargs):
124
+ super().set_data(df, sort_df, calc_ma, set_candlecolor, set_volumecolor, calc_info, *args, **kwargs)
125
+ return
126
+
124
127
  def _generate_data(self, df: pd.DataFrame, sort_df, calc_ma, set_candlecolor, set_volumecolor, calc_info, *_, **__):
125
128
  super()._generate_data(df, sort_df, calc_ma, set_candlecolor, set_volumecolor, *_, **__)
126
129
 
@@ -144,19 +147,20 @@ class DataMixin(CollectionMixin):
144
147
  self.df['space_box_candle'] = (self.df[self.high] - self.df[self.low]) / 5
145
148
  self.df['bottom_box_candle'] = self.df[self.low] - self.df['space_box_candle']
146
149
  self.df['top_box_candle'] = self.df[self.high] + self.df['space_box_candle']
147
- if self.volume: self.df['max_box_volume'] = self.df[self.volume] * 1.13
150
+ self.df['height_box_candle'] = self.df['top_box_candle'] - self.df['bottom_box_candle']
151
+ if self.volume: self.df['max_box_volume'] = self.df[self.volume] * 1.15
148
152
  return
149
153
 
150
154
  def _set_lim(self, xmin, xmax, simpler=False, set_ma=True):
151
155
  super()._set_lim(xmin, xmax, simpler, set_ma)
152
156
 
153
157
  psub = (self.price_ymax - self.price_ymin)
154
- self.min_candleboxheight = psub / 8
158
+ self.min_height_box_candle = psub / 8
155
159
 
156
160
  pydistance = psub / 20
157
- self.text_date_price.set_y(self.price_ymin + pydistance)
161
+ self.artist_text_date_price.set_y(self.price_ymin + pydistance)
158
162
 
159
- self.min_volumeboxheight = self.volume_ymax / 4
163
+ self.min_height_box_volume = self.volume_ymax / 4
160
164
 
161
165
  vxsub = self.vxmax - self.vxmin
162
166
  self.vmiddle = self.vxmax - int((vxsub) / 2)
@@ -167,11 +171,11 @@ class DataMixin(CollectionMixin):
167
171
  self.veighth = self.vxmin + int((vxsub) / 8)
168
172
 
169
173
  yvolume = self.volume_ymax * 0.85
170
- self.text_date_volume.set_y(yvolume)
174
+ self.artist_text_date_volume.set_y(yvolume)
171
175
 
172
176
  # 정보 텍스트박스
173
- self.text_price_info.set_y(self.price_ymax - pydistance)
174
- self.text_volume_info.set_y(yvolume)
177
+ self.artist_text_price_info.set_y(self.price_ymax - pydistance)
178
+ self.artist_text_volume_info.set_y(yvolume)
175
179
  return
176
180
 
177
181
 
@@ -200,9 +204,15 @@ class EventMixin(DataMixin):
200
204
  if not ax or e.xdata is None or e.ydata is None:
201
205
  self.in_price_chart, self.in_volume_chart = (False, False)
202
206
  else:
203
- self.in_price_chart = ax is self.ax_price
204
- self.in_volume_chart = False if self.in_price_chart else ax is self.ax_volume
205
-
207
+ if ax is self.ax_price:
208
+ self.in_price_chart = True
209
+ self.in_volume_chart = False
210
+ elif ax is self.ax_volume:
211
+ self.in_price_chart = False
212
+ self.in_volume_chart = True
213
+ else:
214
+ self.in_price_chart = False
215
+ self.in_volume_chart = False
206
216
  return
207
217
 
208
218
  def _get_x(self, e: MouseEvent):
@@ -214,112 +224,159 @@ class EventMixin(DataMixin):
214
224
  return
215
225
 
216
226
 
217
- class LineMixin(EventMixin):
227
+ class CrossLineMixin(EventMixin):
218
228
  digit_price, digit_volume = (0, 0)
219
229
  in_candle, in_volumebar = (False, False)
220
230
 
221
231
  def _on_move(self, e):
222
232
  super()._on_move(e)
223
233
 
224
- self._restore_region()
225
-
226
- if self.in_price_chart: self._on_move_price_chart(e)
227
- elif self.in_volume_chart: self._on_move_volume_chart(e)
228
-
229
- self._blit()
234
+ if self.in_price_chart or self.in_volume_chart:
235
+ self._restore_region()
236
+ self._draw_crossline(e, self.in_price_chart)
237
+ self.figure.canvas.blit()
238
+ else:
239
+ if self._erase_crossline():
240
+ self._restore_region()
241
+ self.figure.canvas.blit()
230
242
  return
231
243
 
232
- def _on_move_price_chart(self, e: MouseEvent):
233
- x, y = (e.xdata, e.ydata)
234
-
235
- self.price_crossline.set_segments([((x, self.price_ymin), (x, self.price_ymax)), ((self.vxmin, y), (self.vxmax, y))])
236
- self.volume_crossline.set_segments([((x, 0), (x, self.volume_ymax))])
237
- self._draw_crossline()
238
-
239
- renderer = self.figure.canvas.renderer
244
+ def _erase_crossline(self):
245
+ seg = self.collection_price_crossline.get_segments()
246
+ if seg:
247
+ self.collection_price_crossline.set_segments([])
248
+ return True
249
+ return False
240
250
 
241
- # 가격
242
- self.text_price.set_text(f'{float_to_str(y, self.digit_price)}{self.unit_price}')
243
- self.text_price.set_x(self.v0 if self.veighth < x else self.vsixth)
244
- self.text_price.set_y(y)
245
- self.text_price.draw(renderer)
251
+ def _draw_crossline(self, e: MouseEvent, in_price_chart):
252
+ x, y = (e.xdata, e.ydata)
246
253
 
247
- index = self.intx
248
- if index is None: self.in_candle = False
254
+ if in_price_chart:
255
+ self.collection_price_crossline.set_segments([((x, self.price_ymin), (x, self.price_ymax)), ((self.vxmin, y), (self.vxmax, y))])
256
+ self.collection_volume_crossline.set_segments([((x, 0), (x, self.volume_ymax))])
249
257
  else:
250
- # 기준시간 표시
251
- self.text_date_volume.set_text(f'{self.df[self.date][index]}')
252
- self.text_date_volume.set_x(x)
253
- self.text_date_volume.draw(renderer)
254
-
255
- # 캔들 강조
256
- low = self.df['bottom_box_candle'][index]
257
- high = self.df['top_box_candle'][index]
258
- sub = high - low
259
- if sub < self.min_candleboxheight:
260
- sub = (self.min_candleboxheight - sub) / 2
261
- low -= sub
262
- high += sub
263
-
264
- if high < y or y < low: self.in_candle = False
265
- else:
266
- self.in_candle = True
267
- x1, x2 = (index-0.3, index+1.4)
268
- self.price_box.set_segments([((x1, high), (x2, high), (x2, low), (x1, low), (x1, high))])
269
- self.price_box.draw(renderer)
270
- return
258
+ self.collection_price_crossline.set_segments([((x, self.price_ymin), (x, self.price_ymax))])
259
+ self.collection_volume_crossline.set_segments([((x, 0), (x, self.volume_ymax)), ((self.vxmin, y), (self.vxmax, y))])
271
260
 
272
- def _draw_crossline(self):
273
261
  renderer = self.figure.canvas.renderer
274
- self.price_crossline.draw(renderer)
275
- self.volume_crossline.draw(renderer)
262
+ self.collection_price_crossline.draw(renderer)
263
+ self.collection_volume_crossline.draw(renderer)
264
+
265
+ self._draw_text_artist(e, in_price_chart)
276
266
  return
277
267
 
278
- def _on_move_volume_chart(self, e: MouseEvent):
268
+ def _draw_text_artist(self, e: MouseEvent, in_price_chart):
279
269
  x, y = (e.xdata, e.ydata)
280
270
 
281
- self.price_crossline.set_segments([((x, self.price_ymin), (x, self.price_ymax))])
282
- self.volume_crossline.set_segments([((x, 0), (x, self.volume_ymax)), ((self.vxmin, y), (self.vxmax, y))])
283
- self._draw_crossline()
284
-
285
- if not self.volume: return
286
-
287
271
  renderer = self.figure.canvas.renderer
272
+ if in_price_chart:
273
+ # 가격
274
+ self.artist_text_price.set_text(f'{float_to_str(y, self.digit_price)}{self.unit_price}')
275
+ self.artist_text_price.set_x(self.v0 if self.veighth < x else self.vsixth)
276
+ self.artist_text_price.set_y(y)
277
+ self.artist_text_price.draw(renderer)
278
+
279
+ if self.intx is not None:
280
+ # 기준시간 표시
281
+ self.artist_text_date_volume.set_text(f'{self.df[self.date][self.intx]}')
282
+ self.artist_text_date_volume.set_x(x)
283
+ self.artist_text_date_volume.draw(renderer)
284
+ else:
285
+ # 거래량
286
+ self.artist_text_volume.set_text(f'{float_to_str(y, self.digit_volume)}{self.unit_volume}')
287
+ self.artist_text_volume.set_x(self.v0 if self.veighth < x else self.vsixth)
288
+ self.artist_text_volume.set_y(y)
289
+ self.artist_text_volume.draw(renderer)
290
+
291
+ if self.intx is not None:
292
+ # 기준시간 표시
293
+ self.artist_text_date_price.set_text(f'{self.df[self.date][self.intx]}')
294
+ self.artist_text_date_price.set_x(x)
295
+ self.artist_text_date_price.draw(renderer)
296
+ return
288
297
 
289
- # 거래량
290
- self.text_volume.set_text(f'{float_to_str(y, self.digit_volume)}{self.unit_volume}')
291
- self.text_volume.set_x(self.v0 if self.veighth < x else self.vsixth)
292
- self.text_volume.set_y(y)
293
- self.text_volume.draw(renderer)
294
298
 
295
- index = self.intx
296
- if index is None: self.in_volumebar = False
297
- else:
298
- # 기준시간 표시
299
- self.text_date_price.set_text(f'{self.df[self.date][index]}')
300
- self.text_date_price.set_x(x)
301
- self.text_date_price.draw(renderer)
299
+ class BoxMixin(CrossLineMixin):
300
+ def _draw_crossline(self, e, in_price_chart):
301
+ super()._draw_crossline(e, in_price_chart)
302
+ self._draw_box_artist(e, in_price_chart)
303
+ return
302
304
 
303
- # 거래량 강조
304
- high = self.df[self.volume][index] * 1.15
305
- low = 0
306
- if high < self.min_volumeboxheight: high = self.min_volumeboxheight
305
+ def _draw_box_artist(self, e: MouseEvent, in_price_chart):
306
+ y = e.ydata
307
307
 
308
- if high < y or y < low: self.in_volumebar = False
308
+ renderer = self.figure.canvas.renderer
309
+ if self.intx is not None:
310
+ if in_price_chart:
311
+ # 박스 크기
312
+ high = self.df['top_box_candle'][self.intx]
313
+ low = self.df['bottom_box_candle'][self.intx]
314
+ height = self.df['height_box_candle'][self.intx]
315
+ if height < self.min_height_box_candle:
316
+ sub = (self.min_height_box_candle - height) / 2
317
+ high, low = (high+sub, low-sub)
318
+
319
+ # 커서가 캔들 사이에 있는지 확인
320
+ if high < y or y < low: self.in_candle = False
321
+ else:
322
+ # 캔들 강조
323
+ self.in_candle = True
324
+ x1, x2 = (self.intx-0.3, self.intx+1.4)
325
+ self.collection_price_box.set_segments([((x1, high), (x2, high), (x2, low), (x1, low), (x1, high))])
326
+ self.collection_price_box.draw(renderer)
309
327
  else:
310
- self.in_volumebar = True
311
- x1, x2 = (index-0.3, index+1.4)
312
- self.volume_box.set_segments([((x1, high), (x2, high), (x2, low), (x1, low), (x1, high))])
313
- self.volume_box.draw(renderer)
328
+ # 거래량 강조
329
+ high = self.df['max_box_volume'][self.intx]
330
+ low = 0
331
+ if high < self.min_height_box_volume: high = self.min_height_box_volume
332
+
333
+ if high < y or y < low: self.in_volumebar = False
334
+ else:
335
+ self.in_volumebar = True
336
+ x1, x2 = (self.intx-0.3, self.intx+1.4)
337
+ self.collection_volume_box.set_segments([((x1, high), (x2, high), (x2, low), (x1, low), (x1, high))])
338
+ self.collection_volume_box.draw(renderer)
314
339
  return
315
340
 
316
341
 
317
- format_candleinfo_ko = '{dt}\n\n종가:  {close}\n등락률: {rate}\n대비:  {compare}\n시가:  {open}({rate_open})\n고가:  {high}({rate_high})\n저가:  {low}({rate_low})\n거래량: {volume}({rate_volume})'
318
- format_volumeinfo_ko = '{dt}\n\n거래량:    {volume}\n거래량증가율: {rate_volume}\n대비:     {compare}'
319
- format_candleinfo_en = '{dt}\n\nclose: {close}\nrate: {rate}\ncompare: {compare}\nopen: {open}({rate_open})\nhigh: {high}({rate_high})\nlow: {low}({rate_low})\nvolume: {volume}({rate_volume})'
320
- format_volumeinfo_en = '{dt}\n\nvolume: {volume}\nvolume rate: {rate_volume}\ncompare: {compare}'
321
-
322
- class InfoMixin(LineMixin):
342
+ format_candleinfo_ko = """\
343
+ {dt}
344
+
345
+ 종가:  {close}
346
+ 등락률: {rate}
347
+ 대비:  {compare}
348
+ 시가:  {open}({rate_open})
349
+ 고가:  {high}({rate_high})
350
+ 저가:  {low}({rate_low})
351
+ 거래량: {volume}({rate_volume})\
352
+ """
353
+ format_volumeinfo_ko = """\
354
+ {dt}
355
+
356
+ 거래량:    {volume}
357
+ 거래량증가율: {rate_volume}
358
+ 대비:     {compare}\
359
+ """
360
+ format_candleinfo_en = """\
361
+ {dt}
362
+
363
+ close: {close}
364
+ rate: {rate}
365
+ compare: {compare}
366
+ open: {open}({rate_open})
367
+ high: {high}({rate_high})
368
+ low: {low}({rate_low})
369
+ volume: {volume}({rate_volume})\
370
+ """
371
+ format_volumeinfo_en = """\
372
+ {dt}
373
+
374
+ volume: {volume}
375
+ volume rate: {rate_volume}
376
+ compare: {compare}\
377
+ """
378
+
379
+ class InfoMixin(BoxMixin):
323
380
  fraction = False
324
381
  format_candleinfo = format_candleinfo_ko
325
382
  format_volumeinfo = format_volumeinfo_ko
@@ -330,46 +387,47 @@ class InfoMixin(LineMixin):
330
387
  self._length_text = self.df[(self.volume if self.volume else self.high)].apply(lambda x: len(f'{x:,}')).max()
331
388
  return
332
389
 
333
- def _on_move_price_chart(self, e):
334
- super()._on_move_price_chart(e)
390
+ def _draw_box_artist(self, e, in_price_chart):
391
+ super()._draw_box_artist(e, in_price_chart)
335
392
 
336
- # 캔들 강조 확인
337
- if not self.in_candle: return
393
+ if self.intx is not None:
394
+ if self.in_candle: self._draw_candle_info_artist(e)
395
+ elif self.in_volumebar: self._draw_volume_info_artist(e)
396
+ return
338
397
 
398
+ def _draw_candle_info_artist(self, e: MouseEvent):
339
399
  # 캔들 정보
340
- self.text_price_info.set_text(self._get_info(self.intx))
400
+ self.artist_text_price_info.set_text(self._get_info(self.intx))
341
401
 
342
- if self.vmiddle < e.xdata: self.text_price_info.set_x(self.v0)
402
+ # 정보 텍스트를 중앙에 몰리게 설정할 수도 있지만,
403
+ # 그런 경우 차트를 가리므로 좌우 끝단에 위치하도록 설정
404
+ if self.vmiddle < e.xdata:
405
+ self.artist_text_price_info.set_x(self.v0)
343
406
  else:
344
- # self.text_price_info.set_x(self.vmax - self.x_distance)
345
- # self.text_price_info.set_horizontalalignment('right')
407
+ # self.artist_text_price_info.set_x(self.vmax - self.x_distance)
408
+ # self.artist_text_price_info.set_horizontalalignment('right')
346
409
  # 텍스트박스 크기 가져오기
347
- bbox = self.text_price_info.get_window_extent().transformed(self.ax_price.transData.inverted())
410
+ bbox = self.artist_text_price_info.get_window_extent().transformed(self.ax_price.transData.inverted())
348
411
  width = bbox.x1 - bbox.x0
349
- self.text_price_info.set_x(self.v1 - width)
412
+ self.artist_text_price_info.set_x(self.v1 - width)
350
413
 
351
- self.text_price_info.draw(self.figure.canvas.renderer)
414
+ self.artist_text_price_info.draw(self.figure.canvas.renderer)
352
415
  return
353
416
 
354
- def _on_move_volume_chart(self, e):
355
- super()._on_move_volume_chart(e)
356
-
357
- # 거래량 강조 확인
358
- if not self.in_volumebar: return
359
-
417
+ def _draw_volume_info_artist(self, e: MouseEvent):
360
418
  # 거래량 정보
361
- self.text_volume_info.set_text(self._get_info(self.intx, is_price=False))
419
+ self.artist_text_volume_info.set_text(self._get_info(self.intx, is_price=False))
362
420
 
363
- if self.vmiddle < e.xdata: self.text_volume_info.set_x(self.v0)
421
+ if self.vmiddle < e.xdata: self.artist_text_volume_info.set_x(self.v0)
364
422
  else:
365
- # self.text_volume_info.set_x(self.vmax - self.x_distance)
366
- # self.text_volume_info.set_horizontalalignment('right')
423
+ # self.artist_text_volume_info.set_x(self.vmax - self.x_distance)
424
+ # self.artist_text_volume_info.set_horizontalalignment('right')
367
425
  # 텍스트박스 크기 가져오기
368
- bbox = self.text_volume_info.get_window_extent().transformed(self.ax_price.transData.inverted())
426
+ bbox = self.artist_text_volume_info.get_window_extent().transformed(self.ax_price.transData.inverted())
369
427
  width = bbox.x1 - bbox.x0
370
- self.text_volume_info.set_x(self.v1 - width)
428
+ self.artist_text_volume_info.set_x(self.v1 - width)
371
429
 
372
- self.text_volume_info.draw(self.figure.canvas.renderer)
430
+ self.artist_text_volume_info.draw(self.figure.canvas.renderer)
373
431
  return
374
432
 
375
433
  def _get_info(self, index, is_price=True):
@@ -452,17 +510,13 @@ class BaseMixin(InfoMixin):
452
510
 
453
511
 
454
512
  class Chart(BaseMixin, Mixin):
455
- def _add_collection(self):
456
- super()._add_collection()
457
- return self.add_artist()
458
-
459
513
  def _draw_artist(self):
460
514
  super()._draw_artist()
461
515
  return self.draw_artist()
462
516
 
463
- def _get_segments(self):
464
- self.generate_data()
465
- return super()._get_segments()
517
+ def _set_lim(self, xmin, xmax, simpler=False, set_ma=True):
518
+ super()._set_lim(xmin, xmax, simpler, set_ma)
519
+ return self.on_change_xlim(xmin, xmax, simpler, set_ma)
466
520
 
467
521
  def _on_draw(self, e):
468
522
  super()._on_draw(e)
@@ -472,21 +526,6 @@ class Chart(BaseMixin, Mixin):
472
526
  self.on_pick(e)
473
527
  return super()._on_pick(e)
474
528
 
475
- def _set_candle_segments(self, index_start, index_end):
476
- super()._set_candle_segments(index_start, index_end)
477
- self.set_segment(index_start, index_end)
478
- return
479
-
480
- def _set_wick_segments(self, index_start, index_end, simpler=False):
481
- super()._set_wick_segments(index_start, index_end, simpler)
482
- self.set_segment(index_start, index_end, simpler)
483
- return
484
-
485
- def _set_line_segments(self, index_start, index_end, simpler=False, set_ma=True):
486
- super()._set_line_segments(index_start, index_end, simpler, set_ma)
487
- self.set_segment(index_start, index_end, simpler, set_ma)
488
- return
489
-
490
529
  def _on_move(self, e):
491
530
  super()._on_move(e)
492
531
  return self.on_move(e)