Skip to content

Commit 15494dd

Browse files
fix: add html metrics support for compare (#1744)
* fix: add html metrics support for compare * fix: add html metrics support for compare * fix(linting): code formatting * chore: fix test to include request header * fix(linting): code formatting * chore: add unit tests for the compat file * fix(linting): code formatting --------- Co-authored-by: Azory YData Bot <azory@ydata.ai>
1 parent 45c47c7 commit 15494dd

File tree

4 files changed

+110
-21
lines changed

4 files changed

+110
-21
lines changed

src/ydata_profiling/report/presentation/core/scores.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
from typing import Any, Dict, List, Optional
55

6+
from ydata_profiling.config import Style
67
from ydata_profiling.report.presentation.core.item_renderer import ItemRenderer
78

89

@@ -11,15 +12,15 @@ def __init__(
1112
self,
1213
items: List[Dict],
1314
overall_score: float,
15+
style: Style,
1416
name: Optional[str],
15-
caption: Optional[str],
1617
**kwargs
1718
):
1819
content = {
1920
"items": items,
2021
"overall_score": overall_score,
2122
"name": name,
22-
"caption": caption,
23+
"style": style,
2324
}
2425

2526
super().__init__("scores", content=content, **kwargs)
Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,78 @@
11
<style>
22
.progress {
3-
height: 12px;
3+
height: 18px;
44
border-radius: 6px;
5+
font-size: 0.9rem;
56
}
67

78
.overall-score {
89
font-size: 2.5rem;
910
}
11+
12+
.metric-subtitle {
13+
font-size: 0.9rem;
14+
color: #6c757d;
15+
}
16+
17+
.dual-metric {
18+
display: flex;
19+
justify-content: space-around;
20+
align-items: center;
21+
flex-wrap: wrap;
22+
gap: 1rem;
23+
}
24+
25+
.dual-metric .metric {
26+
min-width: 120px;
27+
}
28+
29+
.card.metric-card {
30+
min-height: 105px; /* Maior altura mínima do cartão */
31+
}
1032
</style>
1133

1234
<div class="container my-5">
1335
<!-- Overall Score -->
1436
<div class="row justify-content-center text-center mb-sm-3">
1537
<div class="col-12">
16-
<div class="card shadow-sm p-4">
17-
<h5 class="text-muted mb-2">Overall Data Quality Score</h5>
18-
<div class="overall-score fw-bold text-primary">{{ overall_score }}</div>
19-
</div>
38+
<div class="card shadow-sm p-4">
39+
<h5 class="text-muted mb-3">Overall Data Quality Score</h5>
40+
<div class="dual-metric">
41+
{% for i in range(overall_score | length) %}
42+
<div class="metric">
43+
{% if overall_score | length > 1 %}
44+
<div class="metric-subtitle">{{ name[i]}}</div>
45+
{% endif %}
46+
<div class="overall-score fw-bold" style="color: {{ style.primary_color }}">{{ overall_score[i]}}</div>
47+
</div>
48+
{% endfor %}
49+
</div>
50+
</div>
2051
</div>
2152
</div>
2253

2354
<!-- Metrics -->
24-
<div class="row g-4 text-center">
55+
<div class="row g-4 text-center">
2556
{% for metric in items %}
2657
<div class="col-lg-4 col-md-6 col-sm-12">
27-
<div class="card shadow-sm p-3 h-100">
28-
<div class="h6 text-muted">{{ metric.name }}</div>
29-
<div class="progress bg-light">
30-
<div
31-
class="progress-bar"
32-
role="progressbar"
33-
style="width: {{ metric.value }}%; background-color: {{ metric.color }};"
34-
aria-valuenow="{{ metric.value }}"
35-
aria-valuemin="0"
36-
aria-valuemax="100">
58+
<div class="card shadow-sm p-3 h-100 metric-card">
59+
<div class="h6 text-muted mb-2">{{ metric.name }}</div>
60+
{% for j in range(metric.submetrics| length) %}
61+
{% if metric.submetrics | length > 1 %}
62+
<div class="metric-subtitle text-start">{{ name[j] }}</div>
63+
{% endif %}
64+
<div class="progress mb-2 bg-light">
65+
<div
66+
class="progress-bar"
67+
style="width: {{ metric.submetrics[j].value }}%; background-color: {{ metric.submetrics[j].color}};">
68+
{{ metric.submetrics[j].value }}%
69+
</div>
3770
</div>
38-
</div>
39-
<div class="fw-bold mt-2" style="color: {{ metric.color }};">{{ metric.value }}%</div>
71+
{% endfor %}
4072
</div>
4173
</div>
4274
{% endfor %}
4375
</div>
4476
</div>
77+
78+

tests/issues/test_issue537.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,15 @@ def test_multiprocessing_describe1d(config, summarizer, typeset):
3434

3535
def download_and_process_data():
3636
"""Downloads and processes the dataset into a Pandas DataFrame."""
37-
response = requests.get("https://ndownloader.figshare.com/files/5976042")
37+
headers = {
38+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
39+
"AppleWebKit/537.36 (KHTML, like Gecko) "
40+
"Chrome/122.0.0.0 Safari/537.36"
41+
}
42+
response = requests.get(
43+
"https://ndownloader.figshare.com/files/5976042", headers=headers
44+
)
45+
3846
response.raise_for_status() # Ensure successful download
3947

4048
file = decompress(response.content)

tests/unit/test_pandas/test_compat.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import unittest
2+
3+
import pandas as pd
4+
5+
from ydata_profiling.utils.compat import optional_option_context, pandas_version_info
6+
7+
8+
class TestCompatUtils(unittest.TestCase):
9+
def test_pandas_version_info_format(self):
10+
version_info = pandas_version_info()
11+
self.assertIsInstance(version_info, tuple)
12+
self.assertTrue(all(isinstance(i, int) for i in version_info))
13+
14+
expected_prefix = tuple(
15+
int(x) for x in pd.__version__.split(".")[: len(version_info)]
16+
)
17+
self.assertEqual(version_info, expected_prefix)
18+
19+
def test_optional_option_context_with_existing_option(self):
20+
option = "display.max_rows"
21+
original_value = pd.get_option(option)
22+
23+
with optional_option_context(option, 123):
24+
self.assertEqual(pd.get_option(option), 123)
25+
26+
self.assertEqual(pd.get_option(option), original_value)
27+
28+
def test_optional_option_context_with_missing_option(self):
29+
class FakeOptionContext:
30+
def __init__(self, *args, **kwargs):
31+
raise pd.errors.OptionError("Simulated OptionError")
32+
33+
original_option_context = pd.option_context
34+
pd.option_context = FakeOptionContext
35+
36+
try:
37+
# Should not raise, even though the option is invalid
38+
with optional_option_context("non.existent.option", 456):
39+
pass
40+
finally:
41+
# Restore the original option_context
42+
pd.option_context = original_option_context
43+
44+
45+
if __name__ == "__main__":
46+
unittest.main()

0 commit comments

Comments
 (0)