seolpyo-mplchart 1.4.1__py3-none-any.whl → 2.0.0.3__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.
Files changed (44) hide show
  1. seolpyo_mplchart/__init__.py +144 -308
  2. seolpyo_mplchart/_chart/__init__.py +137 -0
  3. seolpyo_mplchart/_chart/_base.py +217 -0
  4. seolpyo_mplchart/_chart/_cursor/__init__.py +2 -0
  5. seolpyo_mplchart/_chart/_cursor/_artist.py +217 -0
  6. seolpyo_mplchart/_chart/_cursor/_cursor.py +165 -0
  7. seolpyo_mplchart/_chart/_cursor/_info.py +187 -0
  8. seolpyo_mplchart/_chart/_draw/__init__.py +2 -0
  9. seolpyo_mplchart/_chart/_draw/_artist.py +50 -0
  10. seolpyo_mplchart/_chart/_draw/_data.py +314 -0
  11. seolpyo_mplchart/_chart/_draw/_draw.py +103 -0
  12. seolpyo_mplchart/_chart/_draw/_lim.py +265 -0
  13. seolpyo_mplchart/_chart/_slider/__init__.py +1 -0
  14. seolpyo_mplchart/_chart/_slider/_base.py +268 -0
  15. seolpyo_mplchart/_chart/_slider/_data.py +105 -0
  16. seolpyo_mplchart/_chart/_slider/_mouse.py +176 -0
  17. seolpyo_mplchart/_chart/_slider/_nav.py +204 -0
  18. seolpyo_mplchart/_chart/test.py +121 -0
  19. seolpyo_mplchart/_config/__init__.py +3 -0
  20. seolpyo_mplchart/_config/ax.py +28 -0
  21. seolpyo_mplchart/_config/candle.py +30 -0
  22. seolpyo_mplchart/_config/config.py +21 -0
  23. seolpyo_mplchart/_config/cursor.py +49 -0
  24. seolpyo_mplchart/_config/figure.py +41 -0
  25. seolpyo_mplchart/_config/format.py +51 -0
  26. seolpyo_mplchart/_config/ma.py +15 -0
  27. seolpyo_mplchart/_config/slider/__init__.py +2 -0
  28. seolpyo_mplchart/_config/slider/config.py +24 -0
  29. seolpyo_mplchart/_config/slider/figure.py +20 -0
  30. seolpyo_mplchart/_config/slider/nav.py +9 -0
  31. seolpyo_mplchart/_config/unit.py +19 -0
  32. seolpyo_mplchart/_config/utils.py +67 -0
  33. seolpyo_mplchart/_config/volume.py +26 -0
  34. seolpyo_mplchart/_cursor.py +27 -25
  35. seolpyo_mplchart/_draw.py +7 -18
  36. seolpyo_mplchart/_slider.py +26 -20
  37. seolpyo_mplchart/test.py +172 -56
  38. seolpyo_mplchart/xl_to_dict.py +47 -0
  39. seolpyo_mplchart-2.0.0.3.dist-info/METADATA +710 -0
  40. seolpyo_mplchart-2.0.0.3.dist-info/RECORD +50 -0
  41. {seolpyo_mplchart-1.4.1.dist-info → seolpyo_mplchart-2.0.0.3.dist-info}/WHEEL +1 -1
  42. seolpyo_mplchart-1.4.1.dist-info/METADATA +0 -57
  43. seolpyo_mplchart-1.4.1.dist-info/RECORD +0 -17
  44. {seolpyo_mplchart-1.4.1.dist-info → seolpyo_mplchart-2.0.0.3.dist-info}/top_level.txt +0 -0
seolpyo_mplchart/test.py CHANGED
@@ -1,71 +1,187 @@
1
- import json
2
1
  import sys
3
2
  from pathlib import Path
3
+ name_pkg = 'seolpyo_mplchart'
4
+ path_pkg = Path(__file__)
5
+ while path_pkg.name != name_pkg:
6
+ path_pkg = path_pkg.parent
7
+ sys.path = [path_pkg.parent.__str__()] + sys.path
4
8
 
5
- import pandas as pd
9
+ import json
10
+ import tkinter as tk
11
+ from tkinter import filedialog
6
12
 
7
- sys.path.insert(0, Path(__file__).parent.parent.__str__())
8
- # print(f'{sys.path=}')
13
+ import pandas as pd
14
+ import matplotlib.pyplot as plt
15
+ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
9
16
 
10
17
  import seolpyo_mplchart as mc
18
+ from seolpyo_mplchart.xl_to_dict import convert
19
+
20
+
21
+ path_file = path_pkg / 'sample' / 'apple.txt'
22
+ with open(path_file, 'r', encoding='utf-8') as txt:
23
+ data = json.load(txt)
11
24
 
25
+ df = pd.DataFrame(data[:])
12
26
 
13
- class Chart(mc.SliderChart):
14
- format_candleinfo = mc.format_candleinfo_ko + '\nCustom info: {ci}'
15
- format_volumeinfo = mc.format_volumeinfo_ko
16
- min_distance = 5
17
27
 
18
- def __init__(self, *args, **kwargs):
19
- super().__init__(*args, **kwargs)
20
- self.collection_candle.set_linewidth(1.5)
28
+ def test():
29
+ import seolpyo_mplchart as mc
30
+ class C(mc.CursorChart):
31
+ # fraction = True
32
+ # watermark = 0
33
+ theme = 'light'
34
+ limit_wick = 2000
35
+ # limit_ma = None
36
+ # candle_on_ma = False
37
+ # slider_top = False
38
+ def on_click(self, e):
39
+ super().on_click(e)
40
+ # print(f'{e.button=}')
41
+ # print(f'{e.button.__str__()=}')
42
+ if e.button.__str__() == '3':
43
+ # print('refresh')
44
+ if self.theme == 'light':
45
+ self.theme = 'dark'
46
+ self.CONFIG = mc.set_theme(mc.SLIDERCONFIG_EN, theme=self.theme)
47
+ # self.CONFIG.FIGURE.RATIO.price = 18
48
+ # self.CONFIG.FIGURE.RATIO.volume = 4
49
+ else:
50
+ self.theme = 'light'
51
+ self.CONFIG = mc.set_theme(mc.SLIDERCONFIG, theme=self.theme)
52
+ # self.CONFIG.FIGURE.RATIO.slider = 9
53
+ # self.CONFIG.FIGURE.RATIO.price = 9
54
+ # self.CONFIG.FIGURE.RATIO.volume = 9
55
+ self.CONFIG.UNIT.digit = 2
56
+ self.refresh()
57
+ return
58
+ # def set_segments(self):
59
+ # super().set_segments()
60
+ # self.collection_candle.set_linewidth(1.3)
61
+ # return
62
+ # def get_candle_segment(self, *, is_up, x, left, right, top, bottom, high, low):
63
+ # if is_up:
64
+ # return [
65
+ # (x, bottom),
66
+ # (x, low),
67
+ # (x, bottom),
68
+ # (left, bottom),
69
+ # (x, bottom),
70
+ # (x, top),
71
+ # (right, top),
72
+ # (x, top),
73
+ # (x, high),
74
+ # ]
75
+ # else:
76
+ # return [
77
+ # (x, bottom),
78
+ # (x, low),
79
+ # (x, bottom),
80
+ # (right, bottom),
81
+ # (x, bottom),
82
+ # (x, top),
83
+ # (left, top),
84
+ # (x, top),
85
+ # (x, high),
86
+ # ]
87
+ c = C()
88
+ c.key_date = '기준일'
89
+ c.key_open = '시가'
90
+ c.key_high = '고가'
91
+ c.key_low = '저가'
92
+ c.key_close = '종가'
93
+ c.key_volume = '거래량'
94
+ # c.volume = None
95
+ c.set_data(df)
96
+
97
+ plt.show()
98
+ return
99
+
100
+
101
+ class TkChart:
102
+ chart = None
103
+
104
+ def __init__(self, window: tk.Tk):
105
+ window.wm_title('seolpyo tk chart')
106
+ self.window = window
107
+ # self.window.option_add('맑은고딕 14') # 모든 위젯 기본 폰트 크기 설정
108
+ window.protocol('WM_DELETE_WINDOW', lambda *_: (mc.close('all'), window.destroy()))
109
+
110
+ self.add_entry()
21
111
  return
22
112
 
23
- def get_info_kwargs(self, is_price, **kwargs):
24
- if is_price:
25
- kwargs['ci'] = 'You can add Custom text Info or Change text info.'
26
- kwargs['close'] = 'You can Change close price info.'
27
- return kwargs
28
-
29
- def get_candle_segment(self, *, x, left, right, top, bottom, is_up, high, low):
30
- if is_up:
31
- return (
32
- (x, high),
33
- (x, top),
34
- (right, top),
35
- (x, top),
36
- (x, bottom),
37
- (left, bottom),
38
- (x, bottom),
39
- (x, low),
40
- (x, high)
41
- )
42
- else:
43
- return (
44
- (x, high),
45
- (x, bottom),
46
- (right, bottom),
47
- (x, bottom),
48
- (x, top),
49
- (left, top),
50
- (x, top),
51
- (x, low),
52
- (x, high)
53
- )
54
-
55
-
56
-
57
- C = Chart()
58
- path_file = Path(__file__).parent / 'sample/samsung.txt'
59
- # C.format_candleinfo = mc.format_candleinfo_ko
60
- # C.format_volumeinfo = mc.format_volumeinfo_ko
61
- # C.volume = None
113
+ def open_file(self):
114
+ path_file = filedialog.askopenfilename(
115
+ title="Select a file",
116
+ filetypes=(("Xlsx Files", "*.xlsx"), ("All Files", "*.*"),)
117
+ )
118
+ # print(f'{path_file=}')
119
+ if path_file:
120
+ self.filname.config(state="normal") # 잠깐 풀고
121
+ self.filname.delete(0, tk.END)
122
+ self.filname.insert(0, path_file)
123
+ self.filname.config(state="readonly") # 다시 잠금
124
+
125
+ if not self.chart:
126
+ self.add_chart()
127
+ self.set_chart(path_file)
128
+ return path_file
129
+ return
62
130
 
131
+ def add_entry(self):
132
+ frame = tk.Frame(self.window)
133
+ frame.grid(column=0, row=0, sticky='w', padx=10, pady=10)
134
+
135
+ btn = tk.Button(frame, text='파일 열기', command=lambda *_: self.open_file())
136
+ btn.grid(column=0, row=0)
137
+
138
+ self.filname = tk.Entry(frame, state='readonly', width=100)
139
+ self.filname.grid(column=1, row=0, padx=10)
140
+ return
141
+
142
+ def add_chart(self):
143
+ self.chart = mc.SliderChart()
144
+ self.chart.key_date = '기준일'
145
+ self.chart.key_open = '시가'
146
+ self.chart.key_high = '고가'
147
+ self.chart.key_low = '저가'
148
+ self.chart.key_close = '종가'
149
+ self.chart.key_volume = '거래량'
150
+
151
+ frame = tk.Frame(self.window)
152
+ frame.grid(column=0, row=1, sticky='ewsn')
153
+ self.window.columnconfigure(0, weight=1)
154
+ self.window.rowconfigure(1, weight=1)
155
+
156
+ self.agg = FigureCanvasTkAgg(self.chart.figure, frame)
157
+ widget = self.agg.get_tk_widget()
158
+ widget.grid(column=0, row=0, sticky='ewsn')
159
+ frame.columnconfigure(0, weight=1)
160
+ frame.rowconfigure(0, weight=1)
161
+
162
+ return
163
+
164
+ def set_chart(self, path_file):
165
+ data = convert(path_file)
166
+ print(f'{len(data)=:,}')
167
+ df = pd.DataFrame(data)
168
+ self.chart.set_data(df)
169
+ return
170
+
171
+
172
+ def run():
173
+ root = tk.Tk()
174
+ _ = TkChart(root)
175
+ root.mainloop()
176
+ return
177
+
178
+
179
+ def test_tk():
180
+ run()
181
+ return
63
182
 
64
- with open(path_file, 'r', encoding='utf-8') as txt:
65
- data = json.load(txt)
66
- df = pd.DataFrame(data)
67
183
 
68
- C.set_data(df)
184
+ if __name__ == '__main__':
185
+ test()
186
+ # test_tk()
69
187
 
70
- mc.show()
71
- mc.close()
@@ -0,0 +1,47 @@
1
+ from datetime import datetime, timedelta
2
+ from re import findall
3
+ from zipfile import ZipFile
4
+
5
+
6
+ base_date = datetime(1899, 12, 30).date()
7
+
8
+
9
+ def convert(path_file: str, sheet=1, row=4, date='A', Open='B', high='C', low='D', close='E', volume='F'):
10
+ "xlsx 파일에서 주가 정보를 추출합니다."
11
+ zipfile = ZipFile(path_file)
12
+ # print(f'{zipfile.filelist=}')
13
+ a = zipfile.read(f'xl/worksheets/sheet{sheet}.xml')
14
+ # print(f'{a=}')
15
+ # print(f'{type(a)=}')
16
+ b = a.decode('utf-8')
17
+ list_price: list[dict[str, str|int]] = []
18
+ for i in findall('<row.+?</row>', b)[row:]:
19
+ # print()
20
+ # print(f'{i=}')
21
+ dt = findall(f'<c r="{date}[0-9].+?<v>([0-9]+)</v>', i)
22
+ c = findall(f'<c r="{close}[0-9].+?<v>([0-9\.]+)</v>', i)
23
+ o = findall(f'<c r="{Open}[0-9].+?<v>([0-9\.]+)</v>', i)
24
+ h = findall(f'<c r="{high}[0-9].+?<v>([0-9\.]+)</v>', i)
25
+ l = findall(f'<c r="{low}[0-9].+?<v>([0-9\.]+)</v>', i)
26
+ v = findall(f'<c r="{volume}[0-9].+?<v>([0-9]+)</v>', i)
27
+ # print(f'{(dt, c, o, h, l, v)=}')
28
+ if not all([dt, o, h, l, c,]):
29
+ continue
30
+ try:
31
+ dt = base_date + timedelta(int(dt[0]))
32
+ c = float(c[0])
33
+ o = float(o[0])
34
+ h = float(h[0])
35
+ l = float(l[0])
36
+ except:
37
+ continue
38
+ try:
39
+ v = float(v[0])
40
+ except:
41
+ v = 0
42
+ # print(f'{(dt, c, o, h, l, v)=}')
43
+ # if 2020 < dt.year and dt.year < 2024: list_price.append({'기준일': f'{dt}', '종가': c, '시가': o, '고가': h, '저가': l, '거래량': v,})
44
+ list_price.append({'기준일': f'{dt}', '종가': c, '시가': o, '고가': h, '저가': l, '거래량': v,})
45
+ # for i in enumerate(list_price, 1): print(f' {i}')
46
+ return sorted(list_price, key=lambda x: x['기준일'])
47
+