scilens 0.4.3__py3-none-any.whl → 0.4.5__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 (39) hide show
  1. scilens/components/compare_2_files.py +35 -21
  2. scilens/components/compare_floats.py +14 -5
  3. scilens/components/compare_models.py +1 -1
  4. scilens/config/models/app.py +1 -1
  5. scilens/config/models/compare.py +3 -2
  6. scilens/config/models/compare_float_thresholds.py +3 -2
  7. scilens/config/models/execute.py +1 -1
  8. scilens/config/models/execute_and_compare.py +1 -1
  9. scilens/config/models/file_reader.py +1 -1
  10. scilens/config/models/reader_format_cols.py +8 -7
  11. scilens/config/models/reader_format_csv.py +3 -2
  12. scilens/config/models/reader_format_netcdf.py +1 -1
  13. scilens/config/models/reader_format_txt.py +6 -3
  14. scilens/config/models/reader_format_txt_fixed_cols.py +1 -1
  15. scilens/config/models/reader_metrics.py +4 -1
  16. scilens/config/models/readers.py +7 -6
  17. scilens/config/models/report.py +1 -1
  18. scilens/config/models/report_html.py +11 -10
  19. scilens/config/models/report_output.py +1 -1
  20. scilens/readers/cols_dataset.py +14 -13
  21. scilens/readers/reader_csv.py +33 -34
  22. scilens/readers/reader_interface.py +2 -2
  23. scilens/readers/reader_txt.py +38 -21
  24. scilens/report/templates/body_02_tabs.html +2 -2
  25. scilens/report/templates/compare_11_summary.html +5 -69
  26. scilens/report/templates/compare_11_summary_datasets.html +71 -0
  27. scilens/report/templates/compare_11_summary_metrics copy.html +20 -0
  28. scilens/report/templates/compare_11_summary_metrics.html +25 -0
  29. scilens/report/templates/compare_12_sections.html +9 -8
  30. scilens/report/templates/compare_13_section_numbers_table.html +2 -7
  31. scilens/report/templates/html_macros.html +33 -0
  32. scilens/report/templates/html_widget_err.html +5 -0
  33. scilens/report/templates/index.html +1 -0
  34. scilens/report/templates/js_com_page.js +4 -2
  35. scilens/report/templates/style.css +82 -1
  36. {scilens-0.4.3.dist-info → scilens-0.4.5.dist-info}/METADATA +1 -1
  37. {scilens-0.4.3.dist-info → scilens-0.4.5.dist-info}/RECORD +39 -34
  38. {scilens-0.4.3.dist-info → scilens-0.4.5.dist-info}/WHEEL +0 -0
  39. {scilens-0.4.3.dist-info → scilens-0.4.5.dist-info}/entry_points.txt +0 -0
@@ -4,6 +4,7 @@ _D=True
4
4
  _C=False
5
5
  _B='line'
6
6
  _A=None
7
+ import re
7
8
  from scilens.readers.reader_interface import ReaderInterface
8
9
  from scilens.readers.transform import string_2_floats
9
10
  from scilens.config.models import ReaderTxtConfig
@@ -12,35 +13,47 @@ from scilens.components.compare_floats import CompareFloats
12
13
  class ReaderTxt(ReaderInterface):
13
14
  configuration_type_code='txt';category='datalines';extensions=['TXT']
14
15
  def read(A,config):
15
- F='_';B=config;A.reader_options=B;A.get_lines_pre=1;A.get_lines_post=1
16
+ I='_';B=config;A.reader_options=B;A.get_lines_pre=1;A.get_lines_post=1
16
17
  if B.report_lines:
17
18
  C=_C
18
- for(I,G)in B.report_lines.items():
19
- if I==A.origin.short_name:C=_D;A.get_lines_pre=G.pre;A.get_lines_post=G.post
20
- if not C and B.report_lines.get(F):A.get_lines_pre=B.report_lines[F].pre;A.get_lines_post=B.report_lines[F].post
19
+ for(M,J)in B.report_lines.items():
20
+ if M==A.origin.short_name:C=_D;A.get_lines_pre=J.pre;A.get_lines_post=J.post
21
+ if not C and B.report_lines.get(I):A.get_lines_pre=B.report_lines[I].pre;A.get_lines_post=B.report_lines[I].post
21
22
  D=_A
22
23
  if B.ignore:
23
24
  C=_C
24
- for(I,G)in B.ignore.items():
25
- if I==A.origin.short_name:C=_D;D=G
26
- if not C and B.ignore.get(F):D=B.ignore[F]
27
- K=open(A.origin.path,'r',encoding=A.encoding);A.raw_lines=K.readlines();K.close();A.raw_lines_number=len(A.raw_lines);E=[]
25
+ for(M,J)in B.ignore.items():
26
+ if M==A.origin.short_name:C=_D;D=J
27
+ if not C and B.ignore.get(I):D=B.ignore[I]
28
+ P=open(A.origin.path,'r',encoding=A.encoding);A.raw_lines=P.readlines();P.close();A.raw_lines_number=len(A.raw_lines);E=[]
28
29
  if D:
29
- C,O=A.find_patterns_lines_nb([A.pattern for A in D])
30
- for(P,L)in enumerate(D):
31
- H=O[P][_E]
32
- if H:H=A.get_raw_siblings_nb(H,pre=L.pre,post=L.post);E+=H
30
+ C,R=A.find_patterns_lines_nb([A.pattern for A in D])
31
+ for(S,Q)in enumerate(D):
32
+ K=R[S][_E]
33
+ if K:K=A.get_raw_siblings_nb(K,pre=Q.pre,post=Q.post);E+=K
33
34
  E=list(set(E));E.sort()
34
- A.ignore_patterns=[A.pattern for A in D]if D else[];A.ignore_lines=E;A.ignore_lines_number=len(E);A.curves=A.curve_parser(A.raw_lines)if A.curve_parser else _A;J=[]
35
- for(Q,R)in enumerate(A.raw_lines):
36
- M=string_2_floats(R)
37
- if M:
38
- N=Q+1
39
- if not N in E:J.append({_B:N,_F:M})
40
- A.floats_lines=J;A.floats_lines_number=len(J)
35
+ A.ignore_patterns=[A.pattern for A in D]if D else[];A.ignore_lines=E;A.ignore_lines_number=len(E);A.curves=A.curve_parser(A.raw_lines)if A.curve_parser else _A;N=[]
36
+ for(T,L)in enumerate(A.raw_lines):
37
+ G=string_2_floats(L)
38
+ if G:
39
+ H=T+1
40
+ if not H in E:N.append({_B:H,_F:G})
41
+ A.floats_lines=N;A.floats_lines_number=len(N)
41
42
  if B.error_rule_patterns:
42
- C,S=A.find_patterns_lines_nb(B.error_rule_patterns);A.read_data['error_rule_patterns']={'found':C,'data':S}
43
+ C,U=A.find_patterns_lines_nb(B.error_rule_patterns);A.read_data['error_rule_patterns']={'found':C,'data':U}
43
44
  if C:A.read_error='String error pattern found'
45
+ A.metrics=_A
46
+ if B.metrics:
47
+ O={}
48
+ for F in B.metrics:
49
+ L,H=A.find_pattern_first_line(F.pattern)
50
+ if L:
51
+ G=string_2_floats(L)
52
+ if not G:raise ValueError(f"Metric pattern '{F.pattern}' found but no float values in the line number: {H}")
53
+ try:V=G[F.number_position-1]
54
+ except IndexError:raise ValueError(f"Metric pattern '{F.pattern}' found but no float value at position {F.number_position} in the line number: {H}")
55
+ O[F.name or F.pattern]=V
56
+ if O:A.metrics=O
44
57
  def compare(I,compare_floats,param_reader,param_is_ref=_D):
45
58
  U='diff';K=param_is_ref;J=param_reader;A=compare_floats;V,L=A.compare_errors.add_group('node','txt');V,B=A.compare_errors.add_group(_E,_E,parent=L);C=I if K else J;D=I if not K else J;E=_C
46
59
  if C.floats_lines_number!=D.floats_lines_number:L.error=f"Nb number lines 1: {C.floats_lines_number} 2: {D.floats_lines_number} different"
@@ -64,6 +77,10 @@ class ReaderTxt(ReaderInterface):
64
77
  for C in A:
65
78
  if F.find(C)!=-1:map[C].append(E+1);B=_D
66
79
  return B,[{'pattern':A,_E:map[A]}for A in A]
80
+ def find_pattern_first_line(B,pattern):
81
+ for(C,A)in enumerate(B.raw_lines):
82
+ D=re.search(pattern,A)
83
+ if D:return A.strip(),C+1
67
84
  def get_raw_siblings_nb(A,lines_nb_array,pre=_A,post=_A):
68
85
  B=[]
69
86
  for C in lines_nb_array:
@@ -78,4 +95,4 @@ class ReaderTxt(ReaderInterface):
78
95
  if min<0:min=0
79
96
  if max>A.raw_lines_number:max=A.raw_lines_number
80
97
  return''.join([A.raw_lines[B]for B in range(min,max)])
81
- def class_info(A):return{'raw_lines_number':A.raw_lines_number,'ignore_patterns':A.ignore_patterns,'ignore_lines_number':A.ignore_lines_number,'ignore_lines':A.ignore_lines,'floats_lines_number':A.floats_lines_number,'curves':A.curves}
98
+ def class_info(A):return{'raw_lines_number':A.raw_lines_number,'ignore_patterns':A.ignore_patterns,'ignore_lines_number':A.ignore_lines_number,'ignore_lines':A.ignore_lines,'floats_lines_number':A.floats_lines_number,'curves':A.curves,'metrics':A.metrics}
@@ -1,8 +1,8 @@
1
1
  <div id="tabs" class="tabs noselect" style="display: none;">
2
- <div class="tab active" onclick="actions.click_tab(event, 0)">Summary</div>
2
+ <div class="tab active" data-tab-index="0" onclick="actions.click_tab(event, 0)">Summary</div>
3
3
  {% for file in data.files %}
4
4
  {% if not file.skipped %}
5
- <div class="tab {{ ns.statuses[loop.index] }}" onclick="actions.click_tab(event, {{ loop.index }})"><span class="">{{ file.name }}</span></div>
5
+ <div class="tab {{ ns.statuses[loop.index] }}" data-tab-index="{{ loop.index }}" onclick="actions.click_tab(event, {{ loop.index }})"><span class="">{{ file.name }}</span></div>
6
6
  {% endif %}
7
7
  {% endfor %}
8
8
  <div class="tabend"></div>
@@ -13,77 +13,11 @@
13
13
  <!-- EXTRA HTML -->
14
14
  {% if meta.config.extra_html_summary %}{{ meta.config.extra_html_summary }}{% endif %}
15
15
 
16
+ <!-- METRICS -->
17
+ {% include 'compare_11_summary_metrics.html' %}
16
18
  <!-- DATASETS -->
17
- <h3>
18
- Datasets <action data-command="toogle" data-args="section_summary_datasets"></action>
19
- </h3>
19
+ {% include 'compare_11_summary_datasets.html' %}
20
20
 
21
- <div id="section_summary_datasets">
22
- <table class="shadow-lg">
23
- <tr>
24
- <th class="p-2" rowspan="2">#</th>
25
- <th class="p-2" rowspan="2">Status</th>
26
- <th class="p-2" rowspan="2">Name</th>
27
- <th class="p-2" rowspan="2">Details</th>
28
- <th class="p-2" rowspan="2" class="test-bg-50">Open test</th>
29
- <th class="p-2" rowspan="2" class="refe-bg-50">Open Ref</th>
30
- <th class="p-2" rowspan="2">Error</th>
31
- <th class="p-2" colspan="3" >&nbsp;&nbsp;Comparison&nbsp;&nbsp;</th>
32
- <th class="p-2" colspan="2">Nb Lines - Raw&nbsp;&nbsp;&nbsp;</th>
33
- <th class="p-2" colspan="2">Nb Lines - Ignore</th>
34
- <th class="p-2" colspan="2">Nb Lines - Number</th>
35
- <th class="p-2" rowspan="2">Reader</th>
36
- </tr>
37
- <tr>
38
- <th class="p-2" >Err.</th>
39
- <th class="p-2" >Warn.</th>
40
- <th class="p-2" >Diff.</th>
41
- <th class="p-2 test-bg-50">Test</th>
42
- <th class="p-2 refe-bg-50">Ref.</th>
43
- <th class="p-2 test-bg-50">Test</th>
44
- <th class="p-2 refe-bg-50">Ref.</th>
45
- <th class="p-2 test-bg-50">Test</th>
46
- <th class="p-2 refe-bg-50">Ref.</th>
47
- </tr>
48
- {% for file in data.files %}
49
- <tr>
50
- <td>{{ loop.index }}</td>
51
- <td class="{{ ns.statuses[loop.index] }}">{{ ns.statuses[loop.index] }}</td>
52
- <td>{{ file.name }}</td>
53
- <td class="center">{% if not file.skipped %}<button onclick="actions.see_details({{ loop.index }})">[...]</button>{% endif %}</td>
54
- <td class="center test-bg-20">
55
- {% if file.test.origin and file.test.origin.path %}<action data-command="open_file" data-args="{{ file.test.origin.path.replace(meta.execution_dir, "") }}" data-label="[...]"></action>{% endif %}
56
- </td>
57
- <td class="center refe-bg-20">
58
- {% if file.ref.origin and file.ref.origin.path %}<action data-command="open_file" data-args="{{ file.ref.origin.path.replace(meta.execution_dir, "") }}" data-label="[...]"></action>{% endif %}
59
- </td>
60
- <td class="{{ 'ERROR' if file.error else '' }}">
61
- {% if file.error %}<span>{{ file.error }}</span>{% endif %}
62
- </td>
63
- {% if file.comparison_errors and file.comparison %}
64
- <td class="number {{ 'ERROR' if file.comparison_errors.error_nb else '' }}">{{ file.comparison_errors.error_nb }}</td>
65
- <td class="number {{ 'WARNING' if file.comparison_errors.warning_nb else '' }}">{{ file.comparison_errors.warning_nb }}</td>
66
- <td class="number">{{ file.comparison.total_diffs }}</td>
67
- {% elif not file.skipped %}
68
- <td class="ERROR">ERROR</td>
69
- <td class="ERROR">ERROR</td>
70
- <td class="ERROR">ERROR</td>
71
- {% else %}
72
- <td></td>
73
- <td></td>
74
- <td></td>
75
- {% endif %}
76
- <td class="number test-bg-20">{{ file.test.raw_lines_number }}</td>
77
- <td class="number refe-bg-20">{{ file.ref.raw_lines_number }}</td>
78
- <td class="number test-bg-20">{{ file.test.ignore_lines_number }}</td>
79
- <td class="number refe-bg-20">{{ file.ref.ignore_lines_number }}</td>
80
- <td class="number test-bg-20">{{ file.test.floats_lines_number }}</td>
81
- <td class="number refe-bg-20">{{ file.ref.floats_lines_number }}</td>
82
- <td class="">{{ file.test.reader }}</td>
83
- </tr>
84
- {% endfor %}
85
- </table>
86
- </div>
87
21
 
88
22
  <!-- INFO -->
89
23
 
@@ -93,4 +27,6 @@
93
27
  </h3>
94
28
  <div id="section_variables_and_rules" style="display:none;"></div> -->
95
29
 
30
+
31
+
96
32
  </section>
@@ -0,0 +1,71 @@
1
+ <!-- DATASETS -->
2
+ <h3>
3
+ Datasets <action data-command="toogle" data-args="section_summary_datasets"></action>
4
+ </h3>
5
+
6
+ <div id="section_summary_datasets">
7
+ <table class="shadow-lg">
8
+ <tr>
9
+ <th class="p-2" rowspan="2">#</th>
10
+ <th class="p-2" rowspan="2">Status</th>
11
+ <th class="p-2" rowspan="2">Name</th>
12
+ <th class="p-2" rowspan="2">Details</th>
13
+ <th class="p-2" rowspan="2" class="test-bg-50">Open test</th>
14
+ <th class="p-2" rowspan="2" class="refe-bg-50">Open Ref</th>
15
+ <th class="p-2" rowspan="2">Error</th>
16
+ <th class="p-2" colspan="3" >&nbsp;&nbsp;Comparison&nbsp;&nbsp;</th>
17
+ <th class="p-2" colspan="2">Nb Lines - Raw&nbsp;&nbsp;&nbsp;</th>
18
+ <th class="p-2" colspan="2">Nb Lines - Ignore</th>
19
+ <th class="p-2" colspan="2">Nb Lines - Number</th>
20
+ <th class="p-2" rowspan="2">Reader</th>
21
+ </tr>
22
+ <tr>
23
+ <th class="p-2" >Err.</th>
24
+ <th class="p-2" >Warn.</th>
25
+ <th class="p-2" >Diff.</th>
26
+ <th class="p-2 test-bg-50">Test</th>
27
+ <th class="p-2 refe-bg-50">Ref.</th>
28
+ <th class="p-2 test-bg-50">Test</th>
29
+ <th class="p-2 refe-bg-50">Ref.</th>
30
+ <th class="p-2 test-bg-50">Test</th>
31
+ <th class="p-2 refe-bg-50">Ref.</th>
32
+ </tr>
33
+ {% for file in data.files %}
34
+ <tr>
35
+ <td>{{ loop.index }}</td>
36
+ <td class="{{ ns.statuses[loop.index] }}">{{ ns.statuses[loop.index] }}</td>
37
+ <td>{{ file.name }}</td>
38
+ <td class="center">{% if not file.skipped %}<button onclick="actions.see_details({{ loop.index }})">[...]</button>{% endif %}</td>
39
+ <td class="center test-bg-20">
40
+ {% if file.test.origin and file.test.origin.path %}<action data-command="open_file" data-args="{{ file.test.origin.path.replace(meta.execution_dir, "") }}" data-label="[...]"></action>{% endif %}
41
+ </td>
42
+ <td class="center refe-bg-20">
43
+ {% if file.ref.origin and file.ref.origin.path %}<action data-command="open_file" data-args="{{ file.ref.origin.path.replace(meta.execution_dir, "") }}" data-label="[...]"></action>{% endif %}
44
+ </td>
45
+ <td class="{{ 'ERROR' if file.error else '' }}">
46
+ {% if file.error %}<span>{{ file.error }}</span>{% endif %}
47
+ </td>
48
+ {% if file.comparison_errors and file.comparison %}
49
+ <td class="number {{ 'ERROR' if file.comparison_errors.error_nb else '' }}">{{ file.comparison_errors.error_nb }}</td>
50
+ <td class="number {{ 'WARNING' if file.comparison_errors.warning_nb else '' }}">{{ file.comparison_errors.warning_nb }}</td>
51
+ <td class="number">{{ file.comparison.total_diffs }}</td>
52
+ {% elif not file.skipped %}
53
+ <td class="ERROR">ERROR</td>
54
+ <td class="ERROR">ERROR</td>
55
+ <td class="ERROR">ERROR</td>
56
+ {% else %}
57
+ <td></td>
58
+ <td></td>
59
+ <td></td>
60
+ {% endif %}
61
+ <td class="number test-bg-20">{{ file.test.raw_lines_number }}</td>
62
+ <td class="number refe-bg-20">{{ file.ref.raw_lines_number }}</td>
63
+ <td class="number test-bg-20">{{ file.test.ignore_lines_number }}</td>
64
+ <td class="number refe-bg-20">{{ file.ref.ignore_lines_number }}</td>
65
+ <td class="number test-bg-20">{{ file.test.floats_lines_number }}</td>
66
+ <td class="number refe-bg-20">{{ file.ref.floats_lines_number }}</td>
67
+ <td class="">{{ file.test.reader }}</td>
68
+ </tr>
69
+ {% endfor %}
70
+ </table>
71
+ </div>
@@ -0,0 +1,20 @@
1
+
2
+ <h3>
3
+ Metrics <action data-command="toogle" data-args="section_summary_metrics"></action>
4
+ </h3>
5
+ <div id="section_summary_metrics">
6
+
7
+ <div style="display: flex; flex-wrap: wrap;">
8
+
9
+ <div class="shadow-md p-4 rounded-lg " style="width:200px;height: 100px; border: 1px solid #eee;">
10
+ <div class="text-xs text-gray-500">Débit Massique Entrant (kg/s)</div>
11
+ <div class="text-xl font-bold">2.80 / 2.80</div>
12
+ <div class="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700">
13
+ <div class="bg-blue-600 h-2.5 rounded-full" style="width: 45%"></div>
14
+ </div>
15
+ </div>
16
+
17
+ </div>
18
+
19
+ </div>
20
+
@@ -0,0 +1,25 @@
1
+ {% for file in data.files %}
2
+ {% if file.test.metrics %}
3
+ <h3>Metrics <action data-command="toogle" data-args="section_summary_metrics"></action></h3>
4
+ <div id="section_summary_metrics">
5
+ <div style="display: flex; flex-wrap: wrap;">
6
+ <!-- <div class="kpi-container"> -->
7
+ {% for metric_k, metric_test in file.test.metrics.items() %}
8
+ {% set metric_status = file.comparison.metrics[metric_k].status if file.comparison.metrics else None %}
9
+ {% set metric_err_index = file.comparison.metrics[metric_k].err_index if metric_status else None %}
10
+ {% set metric_err = file.comparison_errors[metric_status][metric_err_index].err if metric_err_index else None %}
11
+ {{ macros.kpi_card(
12
+ metric_k,
13
+ metric_test,
14
+ file.ref.metrics[metric_k],
15
+ metric_status,
16
+ metric_err
17
+ ) }}
18
+ {% endfor %}
19
+ </div>
20
+ </div>
21
+ {% endif %}
22
+ {% endfor %}
23
+
24
+
25
+
@@ -28,7 +28,16 @@
28
28
  {% endif %}
29
29
 
30
30
 
31
+ {% if file.test.reader == 'ReaderImg' %}
32
+ {% set img_test = file.test.origin.path.replace(meta.execution_dir, "") %}
33
+ {% set img_ref = file.ref.origin.path.replace(meta.execution_dir, "") %}
31
34
 
35
+ <div>
36
+ <h3>Images</h3>
37
+ <img class="img_reader" src="{{ img_test[1:] if img_test.startswith('/') else img_test }}">
38
+ <img class="img_reader" src="{{ img_ref[1:] if img_ref.startswith('/') else img_ref }}">
39
+ </div>
40
+ {% endif %}
32
41
 
33
42
  <h3>Informations <action data-command="toogle" data-args="info_{{ (file_index-1)|string }}"></action></h3>
34
43
  <div id="info_{{ file_index-1 }}">
@@ -118,14 +127,6 @@
118
127
  <div id="animations_{{ file_index }}" ></div>
119
128
  {% endif %}
120
129
 
121
- <!--img-->
122
- {% if file.test.reader_category == "img" %}
123
-
124
- <img class="img_reader" src="{{ file.name }}">
125
- <img class="img_reader" src="../reference/{{ file.name }}">
126
-
127
- {% endif %}
128
-
129
130
 
130
131
  <!--FRAMESSERIES-->
131
132
  {% if file.test.framesseries %}
@@ -10,7 +10,7 @@
10
10
  <th class="p-2" rowspan="2">Message</th>
11
11
  <th class="p-2" colspan="2">Value</th>
12
12
  <th class="p-2" rowspan="2">Error</th>
13
- <th class="p-2" rowspan="2">Visu</th>
13
+ <th class="p-2" rowspan="2">Diff. Visu.</th>
14
14
  {% if group.type == "lines" %}
15
15
  <th class="p-2" colspan="2">Line Number</th>
16
16
  <th class="p-2" colspan="2">Line(s)</th>
@@ -57,12 +57,7 @@
57
57
  {% endif %}
58
58
  </td>
59
59
  <td>
60
- {% if item.err.test and item.err.reference %}
61
- <div style="width:200px;height:20px">
62
- <div class="test-bg-80" style="width:{{100*(item.err.test|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%;height:10px"></div>
63
- <div class="refe-bg-80" style="width:{{100*(item.err.reference|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%; height:10px"></div>
64
- </div>
65
- {% endif %}
60
+ {{ macros.compare_visu(item.err.test, item.err.reference) }}
66
61
  </td>
67
62
 
68
63
 
@@ -0,0 +1,33 @@
1
+ {% macro compare_visu(test, reference) %}
2
+ {% if test and reference %}
3
+ <div style="width:100%;height:20px">
4
+ <div class="test-bg-80" style="width:{{100*(test|abs)/([(test|abs), (reference|abs)]|max)}}%;height:10px"></div>
5
+ <div class="refe-bg-80" style="width:{{100*(reference|abs)/([(test|abs), (reference|abs)]|max)}}%; height:10px"></div>
6
+ </div>
7
+ {% endif %}
8
+ {% endmacro %}
9
+
10
+ {% macro kpi_card(name, test, reference, status, err) %}
11
+ <div class="kpi-card">
12
+ <div class="text-xs text-gray-500">{{ name }}</div>
13
+ <div>
14
+ <div class="kpi kpi-{{ status }} text-2xl">
15
+ {% if test == reference %}
16
+ =
17
+ {% elif err %}
18
+ {% if err.is_relative %}
19
+ {% set err_per = err.value*100 %}
20
+ {{ ("%." + ( "2" if err_per < 1 else "0" ) + "f")|format(err.value*100) }}%
21
+ {% else %}
22
+ {{ err.value }}
23
+ {% endif %}
24
+ {% else %}
25
+
26
+ {% endif %}
27
+ </div>
28
+ </div>
29
+ <div class="py-2">{{ compare_visu(test, reference) }}</div>
30
+ <div class="kpi number test-bg-20" title="Test">{{test}}</div>
31
+ <div class="kpi number refe-bg-20" title="Reference">{{reference}}</div>
32
+ </div>
33
+ {% endmacro %}
@@ -0,0 +1,5 @@
1
+
2
+ <div style="width:200px;height:20px">
3
+ <div class="test-bg-80" style="width:{{100*(item.err.test|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%;height:10px"></div>
4
+ <div class="refe-bg-80" style="width:{{100*(item.err.reference|abs)/([(item.err.test|abs), (item.err.reference|abs)]|max)}}%; height:10px"></div>
5
+ </div>
@@ -1,3 +1,4 @@
1
+ {% import "html_macros.html" as macros %}
1
2
  {% macro but2(action) %}
2
3
  <button onclick="{{ action }}" type="button" class="px-1 py-1 text-xs text-white bg-blue-700 rounded-lg hover:bg-blue-800">
3
4
  Show/Hide
@@ -152,8 +152,10 @@
152
152
  case "tabs":
153
153
  // tabs active
154
154
  var children = dom.get("tabs").children;
155
- for (i = 0; i < children.length; i++) { children[i].className = children[i].className.replace(" active", "") }
156
- children[parseInt(index)].className += " active";
155
+ for (i = 0; i < children.length; i++) {
156
+ children[i].className = children[i].className.replace(" active", "");
157
+ if (children[i].dataset.tabIndex == index) { children[i].className += " active"; }
158
+ }
157
159
  // display section
158
160
  for (i = 0; i < NB_SECTIONS; i++) {
159
161
  const section = dom.get("section_"+i);
@@ -104,11 +104,20 @@ button {border: 0;user-select: none; /* Standard syntax */ cursor: pointer;}
104
104
 
105
105
  .text-white { color: rgb(255 255 255); }
106
106
 
107
- .text-xs { font-size: .75rem; line-height: 1rem; }
107
+ .text-xs { font-size: .75rem; line-height: 1rem; }
108
+ .text-lg { font-size: 1.125rem; line-height: 1.75rem; }
109
+ .text-xl { font-size: 1.25rem; line-height: 1.75rem; }
110
+ .text-2xl { font-size: 1.5rem; line-height: 2rem; }
111
+ .text-4xl { font-size: 2rem; line-height: 2.5rem; }
112
+
113
+ .text-gray-500 { color: rgb(107 114 128) }
114
+
115
+ .font-bold { font-weight: 700; }
108
116
 
109
117
  .p-1 { padding: .25rem; }
110
118
  .p-2 { padding: .5rem; }
111
119
  .p-3 { padding: .75rem; }
120
+ .p-4 { padding: 1rem; }
112
121
 
113
122
  .py-1 { padding-bottom: .25rem; padding-top: .25rem; }
114
123
  .py-2 { padding-bottom: .5rem; padding-top: .5rem; }
@@ -142,6 +151,8 @@ button {border: 0;user-select: none; /* Standard syntax */ cursor: pointer;}
142
151
  .hover\:bg-blue-800:hover { background-color: rgb(30 66 159); }
143
152
 
144
153
 
154
+ .w-xs { width: 20rem; }
155
+
145
156
  .shadow-sm { box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); }
146
157
  .shadow { box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); }
147
158
  .shadow-md { box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); }
@@ -150,3 +161,73 @@ button {border: 0;user-select: none; /* Standard syntax */ cursor: pointer;}
150
161
  .shadow-2xl { box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); }
151
162
  .shadow-inner { box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); }
152
163
  .shadow-none { box-shadow: 0 0 #0000; }
164
+
165
+
166
+ .kpi-container::after {
167
+ content: "";
168
+ display: table;
169
+ clear: both;
170
+ }
171
+ .kpi-card {
172
+ width: 200px;
173
+ float: left;
174
+ border-radius: 12px;
175
+ padding: 20px;
176
+ margin: 10px;
177
+ box-sizing: border-box;
178
+ box-shadow: 0 0 10px rgba(0,0,0,0.08);
179
+ text-align: center;
180
+ }
181
+ .kpi {
182
+ font-weight: bold;
183
+ padding: 6px 12px;
184
+ border-radius: 20px;
185
+ display: inline-block;
186
+ margin-top: 10px;
187
+ }
188
+ .kpi-success {
189
+ background: #e6f4ea;
190
+ color: #2e7d32;
191
+ }
192
+ .kpi-error {
193
+ background: #fbe9e7;
194
+ color: #c62828;
195
+ }
196
+ .kpi-warning {
197
+ background: #f9fbe7;
198
+ color: #e4d831;
199
+ }
200
+ .gauge {
201
+ width: 80px;
202
+ height: 80px;
203
+ margin: 10px auto;
204
+ }
205
+
206
+ .gauge circle {
207
+ fill: none;
208
+ stroke-width: 10;
209
+ }
210
+
211
+ .gauge-bg {
212
+ stroke: #eee;
213
+ }
214
+
215
+ .gauge-success {
216
+ stroke: #_4caf50;
217
+ }
218
+
219
+ .gauge-failure {
220
+ stroke: #f44336;
221
+ }
222
+ .gauge-over {
223
+ stroke-linecap: round;
224
+ transform: rotate(-90deg);
225
+ transform-origin: center;
226
+ stroke-width: 11 !important;
227
+ }
228
+
229
+ .gauge-text {
230
+ font-size: 14px;
231
+ fill: #333;
232
+ }
233
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scilens
3
- Version: 0.4.3
3
+ Version: 0.4.5
4
4
  Summary: A CesGensLaB framework for data collecting and deep analysis
5
5
  Home-page: https://scilens.dev
6
6
  License: Proprietary