pyxllib 0.3.197__py3-none-any.whl → 0.3.200__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.
- pyxllib/__init__.py +21 -21
- pyxllib/algo/__init__.py +8 -8
- pyxllib/algo/disjoint.py +54 -54
- pyxllib/algo/geo.py +541 -541
- pyxllib/algo/intervals.py +964 -964
- pyxllib/algo/matcher.py +389 -389
- pyxllib/algo/newbie.py +166 -166
- pyxllib/algo/pupil.py +629 -629
- pyxllib/algo/shapelylib.py +67 -67
- pyxllib/algo/specialist.py +241 -241
- pyxllib/algo/stat.py +494 -494
- pyxllib/algo/treelib.py +149 -149
- pyxllib/algo/unitlib.py +66 -66
- pyxllib/autogui/__init__.py +5 -5
- pyxllib/autogui/activewin.py +246 -246
- pyxllib/autogui/all.py +9 -9
- pyxllib/autogui/autogui.py +852 -852
- pyxllib/autogui/uiautolib.py +362 -362
- pyxllib/autogui/virtualkey.py +102 -102
- pyxllib/autogui/wechat.py +827 -827
- pyxllib/autogui/wechat_msg.py +421 -421
- pyxllib/autogui/wxautolib.py +84 -84
- pyxllib/cv/__init__.py +5 -5
- pyxllib/cv/expert.py +267 -267
- pyxllib/cv/imfile.py +159 -159
- pyxllib/cv/imhash.py +39 -39
- pyxllib/cv/pupil.py +9 -9
- pyxllib/cv/rgbfmt.py +1525 -1525
- pyxllib/cv/slidercaptcha.py +137 -137
- pyxllib/cv/trackbartools.py +251 -251
- pyxllib/cv/xlcvlib.py +1040 -1040
- pyxllib/cv/xlpillib.py +423 -423
- pyxllib/data/echarts.py +240 -240
- pyxllib/data/jsonlib.py +89 -89
- pyxllib/data/oss.py +72 -72
- pyxllib/data/pglib.py +1127 -1127
- pyxllib/data/sqlite.py +568 -568
- pyxllib/data/sqllib.py +297 -297
- pyxllib/ext/JLineViewer.py +505 -505
- pyxllib/ext/__init__.py +6 -6
- pyxllib/ext/demolib.py +246 -246
- pyxllib/ext/drissionlib.py +277 -277
- pyxllib/ext/kq5034lib.py +12 -12
- pyxllib/ext/old.py +663 -663
- pyxllib/ext/qt.py +449 -449
- pyxllib/ext/robustprocfile.py +497 -497
- pyxllib/ext/seleniumlib.py +76 -76
- pyxllib/ext/tk.py +173 -173
- pyxllib/ext/unixlib.py +827 -827
- pyxllib/ext/utools.py +351 -351
- pyxllib/ext/webhook.py +124 -119
- pyxllib/ext/win32lib.py +40 -40
- pyxllib/ext/wjxlib.py +88 -88
- pyxllib/ext/wpsapi.py +124 -124
- pyxllib/ext/xlwork.py +9 -9
- pyxllib/ext/yuquelib.py +1105 -1105
- pyxllib/file/__init__.py +17 -17
- pyxllib/file/docxlib.py +761 -761
- pyxllib/file/gitlib.py +309 -309
- pyxllib/file/libreoffice.py +165 -165
- pyxllib/file/movielib.py +148 -148
- pyxllib/file/newbie.py +10 -10
- pyxllib/file/onenotelib.py +1469 -1469
- pyxllib/file/packlib/__init__.py +330 -330
- pyxllib/file/packlib/zipfile.py +2441 -2441
- pyxllib/file/pdflib.py +426 -426
- pyxllib/file/pupil.py +185 -185
- pyxllib/file/specialist/__init__.py +685 -685
- pyxllib/file/specialist/dirlib.py +799 -799
- pyxllib/file/specialist/download.py +193 -193
- pyxllib/file/specialist/filelib.py +2829 -2829
- pyxllib/file/xlsxlib.py +3131 -3131
- pyxllib/file/xlsyncfile.py +341 -341
- pyxllib/prog/__init__.py +5 -5
- pyxllib/prog/cachetools.py +64 -64
- pyxllib/prog/deprecatedlib.py +233 -233
- pyxllib/prog/filelock.py +42 -42
- pyxllib/prog/ipyexec.py +253 -253
- pyxllib/prog/multiprogs.py +940 -940
- pyxllib/prog/newbie.py +451 -451
- pyxllib/prog/pupil.py +1197 -1197
- pyxllib/prog/sitepackages.py +33 -33
- pyxllib/prog/specialist/__init__.py +391 -391
- pyxllib/prog/specialist/bc.py +203 -203
- pyxllib/prog/specialist/browser.py +497 -497
- pyxllib/prog/specialist/common.py +347 -347
- pyxllib/prog/specialist/datetime.py +198 -198
- pyxllib/prog/specialist/tictoc.py +240 -240
- pyxllib/prog/specialist/xllog.py +180 -180
- pyxllib/prog/xlosenv.py +108 -108
- pyxllib/stdlib/__init__.py +17 -17
- pyxllib/stdlib/tablepyxl/__init__.py +10 -10
- pyxllib/stdlib/tablepyxl/style.py +303 -303
- pyxllib/stdlib/tablepyxl/tablepyxl.py +130 -130
- pyxllib/text/__init__.py +8 -8
- pyxllib/text/ahocorasick.py +39 -39
- pyxllib/text/airscript.js +744 -744
- pyxllib/text/charclasslib.py +121 -121
- pyxllib/text/jiebalib.py +267 -267
- pyxllib/text/jinjalib.py +32 -32
- pyxllib/text/jsa_ai_prompt.md +271 -271
- pyxllib/text/jscode.py +922 -922
- pyxllib/text/latex/__init__.py +158 -158
- pyxllib/text/levenshtein.py +303 -303
- pyxllib/text/nestenv.py +1215 -1215
- pyxllib/text/newbie.py +300 -300
- pyxllib/text/pupil/__init__.py +8 -8
- pyxllib/text/pupil/common.py +1121 -1121
- pyxllib/text/pupil/xlalign.py +326 -326
- pyxllib/text/pycode.py +47 -47
- pyxllib/text/specialist/__init__.py +8 -8
- pyxllib/text/specialist/common.py +112 -112
- pyxllib/text/specialist/ptag.py +186 -186
- pyxllib/text/spellchecker.py +172 -172
- pyxllib/text/templates/echart_base.html +10 -10
- pyxllib/text/templates/highlight_code.html +16 -16
- pyxllib/text/templates/latex_editor.html +102 -102
- pyxllib/text/vbacode.py +17 -17
- pyxllib/text/xmllib.py +747 -747
- pyxllib/xl.py +42 -39
- pyxllib/xlcv.py +17 -17
- {pyxllib-0.3.197.dist-info → pyxllib-0.3.200.dist-info}/METADATA +1 -1
- pyxllib-0.3.200.dist-info/RECORD +126 -0
- {pyxllib-0.3.197.dist-info → pyxllib-0.3.200.dist-info}/licenses/LICENSE +190 -190
- pyxllib-0.3.197.dist-info/RECORD +0 -126
- {pyxllib-0.3.197.dist-info → pyxllib-0.3.200.dist-info}/WHEEL +0 -0
pyxllib/data/echarts.py
CHANGED
@@ -1,240 +1,240 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
# @Author : 陈坤泽
|
4
|
-
# @Email : 877362867@qq.com
|
5
|
-
# @Date : 2022/02/09 11:14
|
6
|
-
|
7
|
-
|
8
|
-
"""
|
9
|
-
Apache ECharts: https://echarts.apache.org/zh/index.html
|
10
|
-
python版:pyechats的封装
|
11
|
-
"""
|
12
|
-
|
13
|
-
from pyxllib.prog.pupil import check_install_package
|
14
|
-
|
15
|
-
check_install_package('pyecharts')
|
16
|
-
|
17
|
-
# import types
|
18
|
-
|
19
|
-
import pyecharts
|
20
|
-
from pyecharts import options as opts
|
21
|
-
from pyecharts.commons.utils import JsCode
|
22
|
-
from pyecharts.globals import ChartType
|
23
|
-
from pyecharts import types
|
24
|
-
from pyecharts.charts import Bar, Line, Radar
|
25
|
-
from pyecharts.charts.chart import Chart
|
26
|
-
|
27
|
-
from pyxllib.prog.pupil import inject_members
|
28
|
-
from pyxllib.prog.specialist import TicToc
|
29
|
-
from pyxllib.file.specialist import XlPath
|
30
|
-
|
31
|
-
|
32
|
-
class XlChart(Chart):
|
33
|
-
def set_title(self, title):
|
34
|
-
self.set_global_opts(title_opts=pyecharts.options.TitleOpts(title=title))
|
35
|
-
|
36
|
-
def add_series(self, name, data, *, type=None, color=None, labels=None,
|
37
|
-
**kwargs):
|
38
|
-
""" 垃圾pyecharts,毁我青春~~
|
39
|
-
|
40
|
-
很多图x都不是等间距的,pyecharts处理不等间距x好像有很大的不兼容问题
|
41
|
-
需要手动添加x、y坐标位置
|
42
|
-
|
43
|
-
:param list|tuple labels: 直接提供现成的文本标签
|
44
|
-
|
45
|
-
"""
|
46
|
-
if type is None:
|
47
|
-
type = self.__class__.__name__.lower()
|
48
|
-
|
49
|
-
if labels:
|
50
|
-
s = [[x[0][0], x[1]] for x in zip(data, labels)]
|
51
|
-
fmt = JsCode(f"function(x){{var m = new Map({s}); return m.get(x.value[0]);}}")
|
52
|
-
if 'label' not in kwargs:
|
53
|
-
kwargs['label'] = opts.LabelOpts(is_show=True, formatter=fmt)
|
54
|
-
elif isinstance(kwargs['label'], opts.LabelOpts):
|
55
|
-
kwargs['label'].opts['formatter'] = fmt
|
56
|
-
else:
|
57
|
-
kwargs['label']['show'] = True
|
58
|
-
kwargs['label']['formatter'] = fmt
|
59
|
-
|
60
|
-
self._append_color(color)
|
61
|
-
# self._append_legend(name, is_selected=True)
|
62
|
-
self._append_legend(name)
|
63
|
-
|
64
|
-
self.options.get('series').append(
|
65
|
-
{
|
66
|
-
'type': type,
|
67
|
-
'name': name,
|
68
|
-
'data': data,
|
69
|
-
**kwargs,
|
70
|
-
}
|
71
|
-
)
|
72
|
-
return self
|
73
|
-
|
74
|
-
|
75
|
-
inject_members(XlChart, Chart)
|
76
|
-
|
77
|
-
|
78
|
-
class XlLine(Line):
|
79
|
-
@classmethod
|
80
|
-
def from_dict(cls, yaxis, xaxis=None, *, title=None,
|
81
|
-
xaxis_name=None, yaxis_name=None, **kwargs):
|
82
|
-
""" 查看一个数据的折线图
|
83
|
-
|
84
|
-
:param list|dict yaxis: 列表数据,或者字典name: values表示的多组数据
|
85
|
-
"""
|
86
|
-
c = cls()
|
87
|
-
|
88
|
-
if isinstance(yaxis, (list, tuple)):
|
89
|
-
yaxis = {'value': yaxis}
|
90
|
-
if xaxis is None:
|
91
|
-
xaxis = list(range(max([len(v) for v in yaxis.values()])))
|
92
|
-
c.add_xaxis(xaxis)
|
93
|
-
for k, v in yaxis.items():
|
94
|
-
c.add_yaxis(k, v)
|
95
|
-
|
96
|
-
configs = {
|
97
|
-
'tooltip_opts': opts.TooltipOpts(trigger="axis"),
|
98
|
-
**kwargs,
|
99
|
-
}
|
100
|
-
c.set_global_opts(tooltip_opts=opts.TooltipOpts(trigger="axis"))
|
101
|
-
if title:
|
102
|
-
configs['title_opts'] = opts.TitleOpts(title=title)
|
103
|
-
if xaxis_name:
|
104
|
-
configs['xaxis_opts'] = opts.AxisOpts(name=xaxis_name, axislabel_opts=opts.LabelOpts(rotate=45, interval=0))
|
105
|
-
if yaxis_name:
|
106
|
-
configs['yaxis_opts'] = opts.AxisOpts(name=yaxis_name)
|
107
|
-
c.set_global_opts(**configs)
|
108
|
-
return c
|
109
|
-
|
110
|
-
|
111
|
-
class XlBar(Bar):
|
112
|
-
|
113
|
-
@classmethod
|
114
|
-
def from_dict(cls, yaxis, xaxis=None, *, title=None,
|
115
|
-
xaxis_name=None, yaxis_name=None, **kwargs):
|
116
|
-
""" 查看一个数据的条形图
|
117
|
-
|
118
|
-
:param list|dict yaxis: 列表数据,或者字典name: values表示的多组数据
|
119
|
-
"""
|
120
|
-
c = cls()
|
121
|
-
|
122
|
-
if isinstance(yaxis, (list, tuple)):
|
123
|
-
yaxis = {'value': yaxis}
|
124
|
-
if xaxis is None:
|
125
|
-
xaxis = list(range(max([len(v) for v in yaxis.values()])))
|
126
|
-
c.add_xaxis(xaxis)
|
127
|
-
for k, v in yaxis.items():
|
128
|
-
c.add_yaxis(k, v)
|
129
|
-
|
130
|
-
configs = {
|
131
|
-
'tooltip_opts': opts.TooltipOpts(trigger="axis"),
|
132
|
-
**kwargs,
|
133
|
-
}
|
134
|
-
c.set_global_opts(tooltip_opts=opts.TooltipOpts(trigger="axis"))
|
135
|
-
if title:
|
136
|
-
configs['title_opts'] = opts.TitleOpts(title=title)
|
137
|
-
if xaxis_name:
|
138
|
-
configs['xaxis_opts'] = opts.AxisOpts(name=xaxis_name)
|
139
|
-
if yaxis_name:
|
140
|
-
configs['yaxis_opts'] = opts.AxisOpts(name=yaxis_name)
|
141
|
-
c.set_global_opts(**configs)
|
142
|
-
return c
|
143
|
-
|
144
|
-
@classmethod
|
145
|
-
def from_list(cls, yaxis, xaxis=None, *, title=None):
|
146
|
-
"""
|
147
|
-
>> browser(pyecharts.charts.Bar.from_list(numbers))
|
148
|
-
"""
|
149
|
-
return cls.from_dict({'value': list(yaxis)}, xaxis=xaxis, title=title)
|
150
|
-
|
151
|
-
@classmethod
|
152
|
-
def from_data_split_into_groups(cls, data, groups, *, title=None):
|
153
|
-
"""根据给定的组数自动拆分数据并生成条形图
|
154
|
-
:param list data: 数据清单
|
155
|
-
:param int groups: 要拆分成的组数
|
156
|
-
"""
|
157
|
-
# 找到最大值和最小值
|
158
|
-
min_val, max_val = min(data), max(data)
|
159
|
-
|
160
|
-
# 计算间隔
|
161
|
-
interval = (max_val - min_val) / groups
|
162
|
-
|
163
|
-
# 分组和标签
|
164
|
-
group_counts = [0] * groups
|
165
|
-
labels = []
|
166
|
-
# todo 如果数据量特别大,这里应该排序后,再用特殊方法计算分组
|
167
|
-
for value in data:
|
168
|
-
index = min(int((value - min_val) / interval), groups - 1)
|
169
|
-
group_counts[index] += 1
|
170
|
-
|
171
|
-
for i in range(groups):
|
172
|
-
labels.append(f"{min_val + interval * i:.2f}-{min_val + interval * (i + 1):.2f}")
|
173
|
-
# t = cls.from_dict({'value': group_counts}, xaxis=labels, title=title)
|
174
|
-
|
175
|
-
return cls.from_dict({'value': group_counts}, xaxis=labels, title=title)
|
176
|
-
|
177
|
-
|
178
|
-
class XlRadar(Radar):
|
179
|
-
""" 雷达图 """
|
180
|
-
|
181
|
-
def __init__(self, *args, **kwargs):
|
182
|
-
super().__init__(*args, **kwargs)
|
183
|
-
self.color_idx = 0
|
184
|
-
|
185
|
-
def add(
|
186
|
-
self,
|
187
|
-
series_name: str,
|
188
|
-
data: types.Sequence[types.Union[opts.RadarItem, dict]],
|
189
|
-
*,
|
190
|
-
label_opts=None,
|
191
|
-
color: types.Optional[str] = None,
|
192
|
-
linestyle_opts=None,
|
193
|
-
**kwargs
|
194
|
-
):
|
195
|
-
""" 标准库(2.0.5版)的雷达图颜色渲染有问题,这里要增加一个修正过程 """
|
196
|
-
if label_opts is None:
|
197
|
-
label_opts = opts.LabelOpts(is_show=False)
|
198
|
-
|
199
|
-
if linestyle_opts is None:
|
200
|
-
linestyle_opts = opts.LineStyleOpts(color=self.colors[self.color_idx % len(self.colors)])
|
201
|
-
self.color_idx += 1
|
202
|
-
elif linestyle_opts.get('color') is None:
|
203
|
-
linestyle_opts.update(color=self.colors[self.color_idx % len(self.colors)])
|
204
|
-
self.color_idx += 1
|
205
|
-
|
206
|
-
if color is None:
|
207
|
-
color = linestyle_opts.get('color')
|
208
|
-
|
209
|
-
return super(XlRadar, self).add(series_name, data,
|
210
|
-
label_opts=label_opts,
|
211
|
-
color=color,
|
212
|
-
linestyle_opts=linestyle_opts,
|
213
|
-
**kwargs)
|
214
|
-
|
215
|
-
|
216
|
-
inject_members(XlBar, Bar)
|
217
|
-
|
218
|
-
|
219
|
-
def render_echart_html(title='Awesome-pyecharts', body=''):
|
220
|
-
from pyxllib.text.xmllib import get_jinja_template
|
221
|
-
return get_jinja_template('echart_base.html').render(title=title, body=body)
|
222
|
-
|
223
|
-
|
224
|
-
# 绘制帕累托累计图
|
225
|
-
def draw_pareto_chart(data, accuracy=0.1, *, title='帕累托累积权重', value_unit_type='K'):
|
226
|
-
from pyxllib.algo.stat import pareto_accumulate
|
227
|
-
pts, labels = pareto_accumulate(data, accuracy=accuracy, value_unit_type=value_unit_type)
|
228
|
-
x = Line()
|
229
|
-
x.add_series(title, pts, labels=labels, label={'position': 'right'})
|
230
|
-
x.set_global_opts(
|
231
|
-
# x轴末尾要故意撑大一些,不然有部分内容会显示不全
|
232
|
-
xaxis_opts=opts.AxisOpts(name='条目数', max_=int(float(f'{pts[-1][0] * 1.2:.2g}'))),
|
233
|
-
yaxis_opts=opts.AxisOpts(name='累积和')
|
234
|
-
)
|
235
|
-
return x
|
236
|
-
|
237
|
-
|
238
|
-
if __name__ == '__main__':
|
239
|
-
with TicToc(__name__):
|
240
|
-
pass
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Author : 陈坤泽
|
4
|
+
# @Email : 877362867@qq.com
|
5
|
+
# @Date : 2022/02/09 11:14
|
6
|
+
|
7
|
+
|
8
|
+
"""
|
9
|
+
Apache ECharts: https://echarts.apache.org/zh/index.html
|
10
|
+
python版:pyechats的封装
|
11
|
+
"""
|
12
|
+
|
13
|
+
from pyxllib.prog.pupil import check_install_package
|
14
|
+
|
15
|
+
check_install_package('pyecharts')
|
16
|
+
|
17
|
+
# import types
|
18
|
+
|
19
|
+
import pyecharts
|
20
|
+
from pyecharts import options as opts
|
21
|
+
from pyecharts.commons.utils import JsCode
|
22
|
+
from pyecharts.globals import ChartType
|
23
|
+
from pyecharts import types
|
24
|
+
from pyecharts.charts import Bar, Line, Radar
|
25
|
+
from pyecharts.charts.chart import Chart
|
26
|
+
|
27
|
+
from pyxllib.prog.pupil import inject_members
|
28
|
+
from pyxllib.prog.specialist import TicToc
|
29
|
+
from pyxllib.file.specialist import XlPath
|
30
|
+
|
31
|
+
|
32
|
+
class XlChart(Chart):
|
33
|
+
def set_title(self, title):
|
34
|
+
self.set_global_opts(title_opts=pyecharts.options.TitleOpts(title=title))
|
35
|
+
|
36
|
+
def add_series(self, name, data, *, type=None, color=None, labels=None,
|
37
|
+
**kwargs):
|
38
|
+
""" 垃圾pyecharts,毁我青春~~
|
39
|
+
|
40
|
+
很多图x都不是等间距的,pyecharts处理不等间距x好像有很大的不兼容问题
|
41
|
+
需要手动添加x、y坐标位置
|
42
|
+
|
43
|
+
:param list|tuple labels: 直接提供现成的文本标签
|
44
|
+
|
45
|
+
"""
|
46
|
+
if type is None:
|
47
|
+
type = self.__class__.__name__.lower()
|
48
|
+
|
49
|
+
if labels:
|
50
|
+
s = [[x[0][0], x[1]] for x in zip(data, labels)]
|
51
|
+
fmt = JsCode(f"function(x){{var m = new Map({s}); return m.get(x.value[0]);}}")
|
52
|
+
if 'label' not in kwargs:
|
53
|
+
kwargs['label'] = opts.LabelOpts(is_show=True, formatter=fmt)
|
54
|
+
elif isinstance(kwargs['label'], opts.LabelOpts):
|
55
|
+
kwargs['label'].opts['formatter'] = fmt
|
56
|
+
else:
|
57
|
+
kwargs['label']['show'] = True
|
58
|
+
kwargs['label']['formatter'] = fmt
|
59
|
+
|
60
|
+
self._append_color(color)
|
61
|
+
# self._append_legend(name, is_selected=True)
|
62
|
+
self._append_legend(name)
|
63
|
+
|
64
|
+
self.options.get('series').append(
|
65
|
+
{
|
66
|
+
'type': type,
|
67
|
+
'name': name,
|
68
|
+
'data': data,
|
69
|
+
**kwargs,
|
70
|
+
}
|
71
|
+
)
|
72
|
+
return self
|
73
|
+
|
74
|
+
|
75
|
+
inject_members(XlChart, Chart)
|
76
|
+
|
77
|
+
|
78
|
+
class XlLine(Line):
|
79
|
+
@classmethod
|
80
|
+
def from_dict(cls, yaxis, xaxis=None, *, title=None,
|
81
|
+
xaxis_name=None, yaxis_name=None, **kwargs):
|
82
|
+
""" 查看一个数据的折线图
|
83
|
+
|
84
|
+
:param list|dict yaxis: 列表数据,或者字典name: values表示的多组数据
|
85
|
+
"""
|
86
|
+
c = cls()
|
87
|
+
|
88
|
+
if isinstance(yaxis, (list, tuple)):
|
89
|
+
yaxis = {'value': yaxis}
|
90
|
+
if xaxis is None:
|
91
|
+
xaxis = list(range(max([len(v) for v in yaxis.values()])))
|
92
|
+
c.add_xaxis(xaxis)
|
93
|
+
for k, v in yaxis.items():
|
94
|
+
c.add_yaxis(k, v)
|
95
|
+
|
96
|
+
configs = {
|
97
|
+
'tooltip_opts': opts.TooltipOpts(trigger="axis"),
|
98
|
+
**kwargs,
|
99
|
+
}
|
100
|
+
c.set_global_opts(tooltip_opts=opts.TooltipOpts(trigger="axis"))
|
101
|
+
if title:
|
102
|
+
configs['title_opts'] = opts.TitleOpts(title=title)
|
103
|
+
if xaxis_name:
|
104
|
+
configs['xaxis_opts'] = opts.AxisOpts(name=xaxis_name, axislabel_opts=opts.LabelOpts(rotate=45, interval=0))
|
105
|
+
if yaxis_name:
|
106
|
+
configs['yaxis_opts'] = opts.AxisOpts(name=yaxis_name)
|
107
|
+
c.set_global_opts(**configs)
|
108
|
+
return c
|
109
|
+
|
110
|
+
|
111
|
+
class XlBar(Bar):
|
112
|
+
|
113
|
+
@classmethod
|
114
|
+
def from_dict(cls, yaxis, xaxis=None, *, title=None,
|
115
|
+
xaxis_name=None, yaxis_name=None, **kwargs):
|
116
|
+
""" 查看一个数据的条形图
|
117
|
+
|
118
|
+
:param list|dict yaxis: 列表数据,或者字典name: values表示的多组数据
|
119
|
+
"""
|
120
|
+
c = cls()
|
121
|
+
|
122
|
+
if isinstance(yaxis, (list, tuple)):
|
123
|
+
yaxis = {'value': yaxis}
|
124
|
+
if xaxis is None:
|
125
|
+
xaxis = list(range(max([len(v) for v in yaxis.values()])))
|
126
|
+
c.add_xaxis(xaxis)
|
127
|
+
for k, v in yaxis.items():
|
128
|
+
c.add_yaxis(k, v)
|
129
|
+
|
130
|
+
configs = {
|
131
|
+
'tooltip_opts': opts.TooltipOpts(trigger="axis"),
|
132
|
+
**kwargs,
|
133
|
+
}
|
134
|
+
c.set_global_opts(tooltip_opts=opts.TooltipOpts(trigger="axis"))
|
135
|
+
if title:
|
136
|
+
configs['title_opts'] = opts.TitleOpts(title=title)
|
137
|
+
if xaxis_name:
|
138
|
+
configs['xaxis_opts'] = opts.AxisOpts(name=xaxis_name)
|
139
|
+
if yaxis_name:
|
140
|
+
configs['yaxis_opts'] = opts.AxisOpts(name=yaxis_name)
|
141
|
+
c.set_global_opts(**configs)
|
142
|
+
return c
|
143
|
+
|
144
|
+
@classmethod
|
145
|
+
def from_list(cls, yaxis, xaxis=None, *, title=None):
|
146
|
+
"""
|
147
|
+
>> browser(pyecharts.charts.Bar.from_list(numbers))
|
148
|
+
"""
|
149
|
+
return cls.from_dict({'value': list(yaxis)}, xaxis=xaxis, title=title)
|
150
|
+
|
151
|
+
@classmethod
|
152
|
+
def from_data_split_into_groups(cls, data, groups, *, title=None):
|
153
|
+
"""根据给定的组数自动拆分数据并生成条形图
|
154
|
+
:param list data: 数据清单
|
155
|
+
:param int groups: 要拆分成的组数
|
156
|
+
"""
|
157
|
+
# 找到最大值和最小值
|
158
|
+
min_val, max_val = min(data), max(data)
|
159
|
+
|
160
|
+
# 计算间隔
|
161
|
+
interval = (max_val - min_val) / groups
|
162
|
+
|
163
|
+
# 分组和标签
|
164
|
+
group_counts = [0] * groups
|
165
|
+
labels = []
|
166
|
+
# todo 如果数据量特别大,这里应该排序后,再用特殊方法计算分组
|
167
|
+
for value in data:
|
168
|
+
index = min(int((value - min_val) / interval), groups - 1)
|
169
|
+
group_counts[index] += 1
|
170
|
+
|
171
|
+
for i in range(groups):
|
172
|
+
labels.append(f"{min_val + interval * i:.2f}-{min_val + interval * (i + 1):.2f}")
|
173
|
+
# t = cls.from_dict({'value': group_counts}, xaxis=labels, title=title)
|
174
|
+
|
175
|
+
return cls.from_dict({'value': group_counts}, xaxis=labels, title=title)
|
176
|
+
|
177
|
+
|
178
|
+
class XlRadar(Radar):
|
179
|
+
""" 雷达图 """
|
180
|
+
|
181
|
+
def __init__(self, *args, **kwargs):
|
182
|
+
super().__init__(*args, **kwargs)
|
183
|
+
self.color_idx = 0
|
184
|
+
|
185
|
+
def add(
|
186
|
+
self,
|
187
|
+
series_name: str,
|
188
|
+
data: types.Sequence[types.Union[opts.RadarItem, dict]],
|
189
|
+
*,
|
190
|
+
label_opts=None,
|
191
|
+
color: types.Optional[str] = None,
|
192
|
+
linestyle_opts=None,
|
193
|
+
**kwargs
|
194
|
+
):
|
195
|
+
""" 标准库(2.0.5版)的雷达图颜色渲染有问题,这里要增加一个修正过程 """
|
196
|
+
if label_opts is None:
|
197
|
+
label_opts = opts.LabelOpts(is_show=False)
|
198
|
+
|
199
|
+
if linestyle_opts is None:
|
200
|
+
linestyle_opts = opts.LineStyleOpts(color=self.colors[self.color_idx % len(self.colors)])
|
201
|
+
self.color_idx += 1
|
202
|
+
elif linestyle_opts.get('color') is None:
|
203
|
+
linestyle_opts.update(color=self.colors[self.color_idx % len(self.colors)])
|
204
|
+
self.color_idx += 1
|
205
|
+
|
206
|
+
if color is None:
|
207
|
+
color = linestyle_opts.get('color')
|
208
|
+
|
209
|
+
return super(XlRadar, self).add(series_name, data,
|
210
|
+
label_opts=label_opts,
|
211
|
+
color=color,
|
212
|
+
linestyle_opts=linestyle_opts,
|
213
|
+
**kwargs)
|
214
|
+
|
215
|
+
|
216
|
+
inject_members(XlBar, Bar)
|
217
|
+
|
218
|
+
|
219
|
+
def render_echart_html(title='Awesome-pyecharts', body=''):
|
220
|
+
from pyxllib.text.xmllib import get_jinja_template
|
221
|
+
return get_jinja_template('echart_base.html').render(title=title, body=body)
|
222
|
+
|
223
|
+
|
224
|
+
# 绘制帕累托累计图
|
225
|
+
def draw_pareto_chart(data, accuracy=0.1, *, title='帕累托累积权重', value_unit_type='K'):
|
226
|
+
from pyxllib.algo.stat import pareto_accumulate
|
227
|
+
pts, labels = pareto_accumulate(data, accuracy=accuracy, value_unit_type=value_unit_type)
|
228
|
+
x = Line()
|
229
|
+
x.add_series(title, pts, labels=labels, label={'position': 'right'})
|
230
|
+
x.set_global_opts(
|
231
|
+
# x轴末尾要故意撑大一些,不然有部分内容会显示不全
|
232
|
+
xaxis_opts=opts.AxisOpts(name='条目数', max_=int(float(f'{pts[-1][0] * 1.2:.2g}'))),
|
233
|
+
yaxis_opts=opts.AxisOpts(name='累积和')
|
234
|
+
)
|
235
|
+
return x
|
236
|
+
|
237
|
+
|
238
|
+
if __name__ == '__main__':
|
239
|
+
with TicToc(__name__):
|
240
|
+
pass
|
pyxllib/data/jsonlib.py
CHANGED
@@ -1,89 +1,89 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
# @Author : 陈坤泽
|
4
|
-
# @Email : 877362867@qq.com
|
5
|
-
# @Date : 2024/04/01
|
6
|
-
|
7
|
-
from collections import Counter
|
8
|
-
|
9
|
-
from pyxllib.prog.pupil import check_install_package
|
10
|
-
|
11
|
-
check_install_package('jmespath')
|
12
|
-
|
13
|
-
import jmespath
|
14
|
-
|
15
|
-
|
16
|
-
class JsonTool:
|
17
|
-
@classmethod
|
18
|
-
def find_paths_by_condition(cls, obj, condition, current_path=''):
|
19
|
-
"""
|
20
|
-
根据提供的条件递归搜索JSON对象,查找满足条件的路径。
|
21
|
-
"""
|
22
|
-
if isinstance(obj, dict):
|
23
|
-
for k, v in obj.items():
|
24
|
-
new_path = f"{current_path}.{k}" if current_path else k
|
25
|
-
if condition(k, v):
|
26
|
-
yield new_path
|
27
|
-
else:
|
28
|
-
if isinstance(v, (dict, list)):
|
29
|
-
yield from JsonTool.find_paths_by_condition(v, condition, new_path)
|
30
|
-
elif isinstance(obj, list):
|
31
|
-
for index, item in enumerate(obj):
|
32
|
-
new_path = f"{current_path}[{index}]"
|
33
|
-
if isinstance(item, (dict, list)):
|
34
|
-
yield from JsonTool.find_paths_by_condition(item, condition, new_path)
|
35
|
-
|
36
|
-
@classmethod
|
37
|
-
def find_paths_with_key(cls, obj, key, current_path=''):
|
38
|
-
"""
|
39
|
-
查找包含指定键名的路径。
|
40
|
-
"""
|
41
|
-
# 定义一个简单的条件函数,仅基于键名
|
42
|
-
condition = lambda k, v: k == key
|
43
|
-
return JsonTool.find_paths_by_condition(obj, condition, current_path)
|
44
|
-
|
45
|
-
|
46
|
-
class JsonlTool:
|
47
|
-
@classmethod
|
48
|
-
def check_key_positions(cls, json_list, key):
|
49
|
-
"""
|
50
|
-
在JSON对象列表中统计每种包含指定键名的路径出现的次数。
|
51
|
-
|
52
|
-
:param json_list: 包含多个JSON对象的列表。
|
53
|
-
:param key: 要查找的键名。
|
54
|
-
:return: 一个Counter对象,统计每种路径出现的次数。
|
55
|
-
"""
|
56
|
-
paths_counter = Counter()
|
57
|
-
for json_obj in json_list:
|
58
|
-
# 使用JsonTool查找当前对象中包含指定键的路径
|
59
|
-
paths = list(JsonTool.find_paths_with_key(json_obj, key))
|
60
|
-
paths_counter.update(paths)
|
61
|
-
|
62
|
-
return paths_counter
|
63
|
-
|
64
|
-
@classmethod
|
65
|
-
def check_path_values(cls, json_list, jmespath_expression, value_extractor=lambda x: x):
|
66
|
-
"""
|
67
|
-
根据提供的jmespath表达式,在JSON对象列表中直接统计表达式取值的次数。
|
68
|
-
支持自定义函数来获取要统计的键。
|
69
|
-
|
70
|
-
:param json_list: 包含多个JSON对象的列表。
|
71
|
-
:param jmespath_expression: 要应用的jmespath表达式。
|
72
|
-
:param value_extractor: 一个函数,用于从jmespath.search的结果中提取要统计的值。
|
73
|
-
:return: 一个Counter对象,统计提取值出现的次数。
|
74
|
-
"""
|
75
|
-
values_counter = Counter()
|
76
|
-
for json_obj in json_list:
|
77
|
-
|
78
|
-
# 使用jmespath搜索当前对象
|
79
|
-
result = jmespath.search(jmespath_expression, json_obj)
|
80
|
-
# 使用自定义的value_extractor函数提取要统计的值
|
81
|
-
extracted_values = value_extractor(result)
|
82
|
-
if not isinstance(extracted_values, list):
|
83
|
-
extracted_values = [extracted_values]
|
84
|
-
|
85
|
-
for value in extracted_values:
|
86
|
-
values_counter[value] += 1
|
87
|
-
|
88
|
-
values_counter = Counter(dict(values_counter.most_common()))
|
89
|
-
return values_counter
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Author : 陈坤泽
|
4
|
+
# @Email : 877362867@qq.com
|
5
|
+
# @Date : 2024/04/01
|
6
|
+
|
7
|
+
from collections import Counter
|
8
|
+
|
9
|
+
from pyxllib.prog.pupil import check_install_package
|
10
|
+
|
11
|
+
check_install_package('jmespath')
|
12
|
+
|
13
|
+
import jmespath
|
14
|
+
|
15
|
+
|
16
|
+
class JsonTool:
|
17
|
+
@classmethod
|
18
|
+
def find_paths_by_condition(cls, obj, condition, current_path=''):
|
19
|
+
"""
|
20
|
+
根据提供的条件递归搜索JSON对象,查找满足条件的路径。
|
21
|
+
"""
|
22
|
+
if isinstance(obj, dict):
|
23
|
+
for k, v in obj.items():
|
24
|
+
new_path = f"{current_path}.{k}" if current_path else k
|
25
|
+
if condition(k, v):
|
26
|
+
yield new_path
|
27
|
+
else:
|
28
|
+
if isinstance(v, (dict, list)):
|
29
|
+
yield from JsonTool.find_paths_by_condition(v, condition, new_path)
|
30
|
+
elif isinstance(obj, list):
|
31
|
+
for index, item in enumerate(obj):
|
32
|
+
new_path = f"{current_path}[{index}]"
|
33
|
+
if isinstance(item, (dict, list)):
|
34
|
+
yield from JsonTool.find_paths_by_condition(item, condition, new_path)
|
35
|
+
|
36
|
+
@classmethod
|
37
|
+
def find_paths_with_key(cls, obj, key, current_path=''):
|
38
|
+
"""
|
39
|
+
查找包含指定键名的路径。
|
40
|
+
"""
|
41
|
+
# 定义一个简单的条件函数,仅基于键名
|
42
|
+
condition = lambda k, v: k == key
|
43
|
+
return JsonTool.find_paths_by_condition(obj, condition, current_path)
|
44
|
+
|
45
|
+
|
46
|
+
class JsonlTool:
|
47
|
+
@classmethod
|
48
|
+
def check_key_positions(cls, json_list, key):
|
49
|
+
"""
|
50
|
+
在JSON对象列表中统计每种包含指定键名的路径出现的次数。
|
51
|
+
|
52
|
+
:param json_list: 包含多个JSON对象的列表。
|
53
|
+
:param key: 要查找的键名。
|
54
|
+
:return: 一个Counter对象,统计每种路径出现的次数。
|
55
|
+
"""
|
56
|
+
paths_counter = Counter()
|
57
|
+
for json_obj in json_list:
|
58
|
+
# 使用JsonTool查找当前对象中包含指定键的路径
|
59
|
+
paths = list(JsonTool.find_paths_with_key(json_obj, key))
|
60
|
+
paths_counter.update(paths)
|
61
|
+
|
62
|
+
return paths_counter
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def check_path_values(cls, json_list, jmespath_expression, value_extractor=lambda x: x):
|
66
|
+
"""
|
67
|
+
根据提供的jmespath表达式,在JSON对象列表中直接统计表达式取值的次数。
|
68
|
+
支持自定义函数来获取要统计的键。
|
69
|
+
|
70
|
+
:param json_list: 包含多个JSON对象的列表。
|
71
|
+
:param jmespath_expression: 要应用的jmespath表达式。
|
72
|
+
:param value_extractor: 一个函数,用于从jmespath.search的结果中提取要统计的值。
|
73
|
+
:return: 一个Counter对象,统计提取值出现的次数。
|
74
|
+
"""
|
75
|
+
values_counter = Counter()
|
76
|
+
for json_obj in json_list:
|
77
|
+
|
78
|
+
# 使用jmespath搜索当前对象
|
79
|
+
result = jmespath.search(jmespath_expression, json_obj)
|
80
|
+
# 使用自定义的value_extractor函数提取要统计的值
|
81
|
+
extracted_values = value_extractor(result)
|
82
|
+
if not isinstance(extracted_values, list):
|
83
|
+
extracted_values = [extracted_values]
|
84
|
+
|
85
|
+
for value in extracted_values:
|
86
|
+
values_counter[value] += 1
|
87
|
+
|
88
|
+
values_counter = Counter(dict(values_counter.most_common()))
|
89
|
+
return values_counter
|