[]
{ if (configuration.isSticky) { fragmentElement.style.height = ‘100%’; // Set the height of the fragment element if sticky configuration is enabled } const parentRow = fragmentElement.closest(‘.row, .ecl-row’); // Find the closest parent row element const selector = buildSelector(configuration); // Build the CSS selector based on configuration const headings = Array.from(parentRow.querySelectorAll(selector)); // Get all headings within the parent row const tableOfContents = buildTableOfContents(headings); // Build the table of contents from the headings const navList = fragmentElement.querySelector(‘.estat-inpage-nav__list’); // Get the navigation list element generateList(navList, tableOfContents); // Generate the navigation list from the table of contents const topMargin = document.querySelector(‘.has-control-menu’) ? 120 : 66; // Determine the top margin based on the presence of a control menu const observeHeadings = new IntersectionObserver( (entries) => observeScrolling(entries, topMargin, headings), { rootMargin: `-${topMargin}px 0px 0px 0px` } // Set the root margin for the intersection observer ); headings.forEach(heading => observeHeadings.observe(heading)); // Observe each heading for intersection changes setupEventListeners(fragmentElement, headings); // Set up event listeners for the navigation elements document.getElementById(‘skip-inpage-navigation’).href = `#${headings[0]?.id}`; // Set the href for the skip navigation link const spinner = fragmentElement.querySelector(‘.ecl-spinner.ecl-spinner–visible’); // Get the spinner element spinner.classList.remove(‘ecl-spinner–visible’); // Hide the spinner fragmentElement.querySelector(‘.estat-inpage-nav’).classList.remove(‘ecl-u-d-none’); // Show the navigation element }); /** * Builds a CSS selector string based on the configuration object. * @param {Object} configuration – Configuration object containing heading levels and other settings. * @returns {string} – The CSS selector string. */ function buildSelector(configuration) { let selector = ”; const deepestLevel = configuration.headingLevel.slice(-1); // Get the deepest heading level from the configuration const topLevel = 2; // Define the top level heading for (let i = topLevel; i topLevel) { selector += ‘, ‘; // Add a comma separator for multiple selectors } selector += `h${i}`; // Add the heading level to the selector if (!configuration.includeNonECLHeadings) { selector += `.ecl-u-type-heading-${i}`; // Add the ECL heading class if non-ECL headings are not included } if (configuration.selectorToExclude) { selector += `:not(${configuration.selectorToExclude})`; // Exclude specific selectors if defined in the configuration } } return selector; } /** * Builds a table of contents array from the provided headings. * @param {Array} headings – Array of heading elements. * @returns {Array} – The table of contents array. */ function buildTableOfContents(headings) { let tableOfContents = []; headings.forEach((heading, i) => { if (!heading.id) { heading.id = ‘estat-inpage-nav-heading-‘ + i; // Assign a unique ID to the heading if it doesn’t have one } const objEl = { ‘id’: heading.id, ‘content’: heading.innerText, level: heading.nodeName.slice(-1) – 1, // Determine the heading level children: [] }; addHeadingToTableOfContents(objEl, tableOfContents); // Add the heading to the table of contents }); return tableOfContents; } /** * Adds a heading object to the table of contents array. * @param {Object} objEl – Heading object to add. * @param {Array} tableOfContents – The table of contents array. */ function addHeadingToTableOfContents(objEl, tableOfContents) { if (objEl.level === 1) { tableOfContents.push(objEl); // Add level 1 headings directly to the table of contents } else if (objEl.level === 2) { tableOfContents[tableOfContents.length – 1].children.push(objEl); // Add level 2 headings as children of the last level 1 heading } else if (objEl.level === 3) { const childrenArr = tableOfContents[tableOfContents.length – 1].children; childrenArr[childrenArr.length – 1].children.push(objEl); // Add level 3 headings as children of the last level 2 heading } } /** * Generates a nested list of navigation links from the table of contents array. * @param {HTMLElement} ulElement – The unordered list element to populate. * @param {Array} headingArray – Array of heading objects. */ function generateList(ulElement, headingArray) { headingArray.forEach((heading, i) => { const li = document.createElement(‘li’); li.className = ‘estat-inpage-nav__list-item’; ulElement.appendChild(li); const link = `${heading.content}` if (heading.children.length > 0) { const containerDiv = document.createElement(‘div’) const button = `
Printing can have negative environmental impacts due to paper waste. We encourage you to explore eco-friendly alternatives. Bookmarking this page in your browser allows you to access it anytime.
This publication can also be converted to PDF, if you have a PDF printer installed on your computer. PDF printers function as virtual printers, enabling you to create digital copies of web pages and access the content offline.
{ const buttonPrintPage = document.getElementById(‘estat-print-page-modal-toggle’); const cookieSkipModal = ‘skipModalBeforePrinting’; if (configuration.displayInPageHeader) { const headerElement = document.querySelector(‘.ecl-page-header .ecl-page-header__meta’) || document.querySelector(‘.ecl-page-header .ecl-page-header__title-container ‘) if (headerElement) { headerElement.prepend(buttonPrintPage); headerElement.classList.add(‘ecl-u-width-100’) } } buttonPrintPage.addEventListener(‘click’, () => { const skipModal = readCookie(cookieSkipModal); if (skipModal == ‘true’) { window.print(); } else { const eclModalElement = document.getElementById(‘estat-print-page-modal’); const eclModal = ECL.components.get(eclModalElement); eclModal.openModal(); } }); document.getElementById(‘print-submit’).addEventListener(‘click’, () => { const skipModal = document.getElementById(‘checkbox-skip-modal’).checked if (skipModal) { writeCookieWithMaxAgeValue(cookieSkipModal, ‘true’, 15768000); } else { deleteCookie(cookieSkipModal); } window.print(); }); });;}());]]>
Government debt at 87.1% and 80.7% respectively
Overview
In the euro area the government deficit to GDP ratio decreased from 3.5% in 2023 to 3.1% in 2024, and in the EU from 3.4% to 3.1%. In the euro area the government debt to GDP ratio slightly increased from 87.0% at the end of 2023 to 87.1% at the end of 2024, and in the EU from 80.5% to 80.7%.
In this release, Eurostat, the statistical office of the European Union, is providing government deficit and debt data for the years 2021-2024, based on figures reported by EU Member States in the second notification in 2025, for the application of the excessive deficit procedure (EDP). This notification is based on the ESA 2010 system of national accounts. This release also includes data on government expenditure and revenue.
|
Deficit and debt data for Euro area and EU |
|||||
|---|---|---|---|---|---|
|
|
|
2021 |
2022 |
2023 |
2024 |
|
|
|
|
|
|
|
|
(million euro) |
12 618 700 |
13 757 926 |
14 663 652 |
15 231 315 |
|
|
(million euro) |
-643 662 |
-466 775 |
-513 481 |
-466 620 |
|
|
% of GDP |
-5.1 |
-3.4 |
-3.5 |
-3.1 |
|
|
% of GDP |
52.0 |
49.9 |
49.4 |
49.5 |
|
|
% of GDP |
46.9 |
46.5 |
45.9 |
46.4 |
|
|
(million euro) |
11 838 348 |
12 286 967 |
12 750 512 |
13 263 357 |
|
|
% of GDP |
93.8 |
89.3 |
87.0 |
87.1 |
|
|
|
|
|
|
|
|
|
(million euro) |
14 792 289 |
16 169 776 |
17 257 316 |
18 015 434 |
|
|
(million euro) |
-683 853 |
-510 836 |
-593 212 |
-565 922 |
|
|
% of GDP |
-4.6 |
-3.2 |
-3.4 |
-3.1 |
|
|
% of GDP |
51.2 |
49.2 |
48.9 |
49.2 |
|
|
% of GDP |
46.5 |
46.0 |
45.5 |
46.0 |
|
|
(million euro) |
12 829 600 |
13 315 508 |
13 894 848 |
14 546 564 |
|
|
% of GDP |
86.7 |
82.3 |
80.5 |
80.7 |
In 2024, all Member States, except Denmark (+4.5%), Cyprus (+4.1%), Ireland (+4.0%), Greece (+1.2%), Luxembourg (+0.9%) and Portugal (+0.5%), reported a deficit. The highest deficits were recorded in Romania (‑9.3%), Poland (-6.5%), France (‑5.8%) and Slovakia (-5.5%). Twelve Member States had deficits equal to or higher than 3% of GDP.
At the end of 2024, the lowest ratios of government debt to GDP were recorded in Estonia (23.5%), Bulgaria (23.8%), Luxembourg (26.3%), Denmark (30.5%), Sweden (34.0%) and Lithuania (38.0%). Twelve Member States had government debt ratios higher than 60% of GDP, with the highest registered in Greece (154.2%), Italy (134.9%), France (113.2%), Belgium (103.9%) and Spain (101.6%).
In 2024, government total expenditure to GDP ratio in the euro area stood at 49.5% of GDP and government total revenue to GDP ratio stood at 46.4%. The figures for the EU were 49.2% and 46.0%, respectively. Government revenue and expenditure ratios increased both in the euro area and the EU, compared to 2023.
Reservations on reported data
Eurostat has no reservations on the data reported by Member States.
Amendment by Eurostat to reported data
Eurostat has made no amendments to the data reported by Member States.
Tables
|
GDP, government deficit/surplus and debt in the EU |
||||
|---|---|---|---|---|
|
2021 |
2022 |
2023 |
2024 |
|
|
|
|
|
|
|
|
(million euro) |
506 047 |
561 309 |
602 376 |
620 272 |
|
(million euro) |
-27 336 |
-20 217 |
-24 134 |
-27 059 |
|
(% of GDP) |
-5.4 |
-3.6 |
-4.0 |
-4.4 |
|
(% of GDP) |
54.9 |
52.5 |
52.8 |
54.1 |
|
(% of GDP) |
49.5 |
48.9 |
48.8 |
49.7 |
|
(million euro) |
550 279 |
580 297 |
617 112 |
644 398 |
|
(% of GDP) |
108.7 |
103.4 |
102.4 |
103.9 |
|
(million euro) |
8 744 |
8 567 |
8 357 |
8 059 |
|
(% of GDP) |
1.7 |
1.5 |
1.4 |
1.3 |
|
|
|
|
|
|
|
(million BGN) |
139 537 |
168 354 |
184 875 |
204 907 |
|
(million BGN) |
-5 526 |
-4 942 |
-3 683 |
-6 240 |
|
(% of GDP) |
-4.0 |
-2.9 |
-2.0 |
-3.0 |
|
(% of GDP) |
41.5 |
41.3 |
38.9 |
39.2 |
|
(% of GDP) |
37.6 |
38.4 |
36.9 |
36.1 |
|
(million BGN) |
33 279 |
37 855 |
42 393 |
48 851 |
|
(% of GDP) |
23.8 |
22.5 |
22.9 |
23.8 |
|
(million BGN) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million CZK) |
6 307 755 |
7 049 872 |
7 659 655 |
8 057 032 |
|
(million CZK) |
-312 308 |
-216 345 |
-286 066 |
-163 487 |
|
(% of GDP) |
-5.0 |
-3.1 |
-3.7 |
-2.0 |
|
(% of GDP) |
45.0 |
43.0 |
43.7 |
42.9 |
|
(% of GDP) |
40.1 |
39.9 |
40.0 |
40.8 |
|
(million CZK) |
2 566 752 |
2 997 632 |
3 234 102 |
3 488 471 |
|
(% of GDP) |
40.7 |
42.5 |
42.2 |
43.3 |
|
(million CZK) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million DKK) |
2 553 261 |
2 831 270 |
2 787 930 |
2 926 878 |
|
(million DKK) |
104 126 |
95 960 |
95 630 |
130 501 |
|
(% of GDP) |
4.1 |
3.4 |
3.4 |
4.5 |
|
(% of GDP) |
49.7 |
45.1 |
47.4 |
47.3 |
|
(% of GDP) |
53.8 |
48.5 |
50.8 |
51.8 |
|
(million DKK) |
1 011 796 |
943 250 |
919 014 |
893 977 |
|
(% of GDP) |
39.6 |
33.3 |
33.0 |
30.5 |
|
(million DKK) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
3 682 340 |
3 989 390 |
4 219 310 |
4 328 970 |
|
(million euro) |
-116 630 |
-76 138 |
-105 249 |
-115 295 |
|
(% of GDP) |
-3.2 |
-1.9 |
-2.5 |
-2.7 |
|
(% of GDP) |
50.7 |
48.6 |
48.1 |
49.4 |
|
(% of GDP) |
47.5 |
46.7 |
45.7 |
46.8 |
|
(million euro) |
2 501 719 |
2 569 046 |
2 630 570 |
2 693 780 |
|
(% of GDP) |
67.9 |
64.4 |
62.3 |
62.2 |
|
(million euro) |
68 128 |
66 900 |
65 755 |
62 928 |
|
(% of GDP) |
1.9 |
1.7 |
1.6 |
1.5 |
|
|
|
|
|
|
|
(million euro) |
31 453 |
36 301 |
38 353 |
39 848 |
|
(million euro) |
-796 |
-359 |
-1 049 |
-689 |
|
(% of GDP) |
-2.5 |
-1.0 |
-2.7 |
-1.7 |
|
(% of GDP) |
42.1 |
40.0 |
43.1 |
44.0 |
|
(% of GDP) |
39.6 |
39.0 |
40.3 |
42.2 |
|
(million euro) |
5 795 |
6 965 |
7 736 |
9 353 |
|
(% of GDP) |
18.4 |
19.2 |
20.2 |
23.5 |
|
(million euro) |
480 |
482 |
481 |
481 |
|
(% of GDP) |
1.5 |
1.3 |
1.3 |
1.2 |
|
|
|
|
|
|
|
(million euro) |
448 445 |
520 718 |
524 729 |
562 794 |
|
(million euro) |
-5 864 |
8 235 |
7 159 |
22 605 |
|
(% of GDP) |
-1.3 |
1.6 |
1.4 |
4.0 |
|
(% of GDP) |
23.5 |
20.7 |
22.2 |
22.4 |
|
(% of GDP) |
22.2 |
22.2 |
23.6 |
26.4 |
|
(million euro) |
235 182 |
223 610 |
219 079 |
215 380 |
|
(% of GDP) |
52.4 |
42.9 |
41.8 |
38.3 |
|
(million euro) |
318 |
284 |
249 |
197 |
|
(% of GDP) |
0.1 |
0.1 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
184 575 |
207 009 |
224 686 |
236 736 |
|
(million euro) |
-13 365 |
-5 324 |
-3 235 |
2 911 |
|
(% of GDP) |
-7.2 |
-2.6 |
-1.4 |
1.2 |
|
(% of GDP) |
56.7 |
53.1 |
49.6 |
48.2 |
|
(% of GDP) |
49.5 |
50.5 |
48.2 |
49.5 |
|
(million euro) |
364 141 |
368 005 |
369 110 |
364 965 |
|
(% of GDP) |
197.3 |
177.8 |
164.3 |
154.2 |
|
(million euro) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
1 235 474 |
1 375 863 |
1 497 761 |
1 594 330 |
|
(million euro) |
-82 174 |
-63 105 |
-50 027 |
-51 267 |
|
(% of GDP) |
-6.7 |
-4.6 |
-3.3 |
-3.2 |
|
(% of GDP) |
49.5 |
46.3 |
45.4 |
45.5 |
|
(% of GDP) |
42.8 |
41.7 |
42.1 |
42.3 |
|
(million euro) |
1 429 404 |
1 504 105 |
1 575 377 |
1 620 573 |
|
(% of GDP) |
115.7 |
109.3 |
105.2 |
101.6 |
|
(million euro) |
29 867 |
29 329 |
28 608 |
27 589 |
|
(% of GDP) |
2.4 |
2.1 |
1.9 |
1.7 |
|
|
|
|
|
|
|
(million euro) |
2 508 102 |
2 653 997 |
2 826 542 |
2 919 900 |
|
(million euro) |
-165 149 |
-125 896 |
-151 709 |
-169 655 |
|
(% of GDP) |
-6.6 |
-4.7 |
-5.4 |
-5.8 |
|
(% of GDP) |
59.5 |
58.4 |
56.9 |
57.3 |
|
(% of GDP) |
52.9 |
53.7 |
51.5 |
51.4 |
|
(million euro) |
2 828 781 |
2 955 639 |
3 102 542 |
3 305 262 |
|
(% of GDP) |
112.8 |
111.4 |
109.8 |
113.2 |
|
(million euro) |
51 150 |
50 228 |
48 993 |
47 248 |
|
(% of GDP) |
2.0 |
1.9 |
1.7 |
1.6 |
|
|
|
|
|
|
|
(million euro) |
58 343 |
67 613 |
79 186 |
85 905 |
|
(million euro) |
-1 501 |
95 |
-622 |
-1 673 |
|
(% of GDP) |
-2.6 |
0.1 |
-0.8 |
-1.9 |
|
(% of GDP) |
48.2 |
45.0 |
46.3 |
48.0 |
|
(% of GDP) |
45.6 |
45.2 |
45.5 |
46.1 |
|
(million euro) |
45 629 |
46 347 |
48 264 |
49 284 |
|
(% of GDP) |
78.2 |
68.5 |
60.9 |
57.4 |
|
(million euro) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
1 842 507 |
1 998 073 |
2 142 602 |
2 199 619 |
|
(million euro) |
-163 535 |
-161 859 |
-153 305 |
-73 937 |
|
(% of GDP) |
-8.9 |
-8.1 |
-7.2 |
-3.4 |
|
(% of GDP) |
56.0 |
54.9 |
53.6 |
50.4 |
|
(% of GDP) |
47.2 |
46.8 |
46.5 |
47.1 |
|
(million euro) |
2 686 729 |
2 764 453 |
2 869 938 |
2 966 915 |
|
(% of GDP) |
145.8 |
138.4 |
133.9 |
134.9 |
|
(million euro) |
44 932 |
44 122 |
43 037 |
41 503 |
|
(% of GDP) |
2.4 |
2.2 |
2.0 |
1.9 |
|
|
|
|
|
|
|
(million euro) |
25 680 |
29 645 |
32 439 |
34 770 |
|
(million euro) |
-407 |
795 |
555 |
1 439 |
|
(% of GDP) |
-1.6 |
2.7 |
1.7 |
4.1 |
|
(% of GDP) |
42.7 |
37.7 |
40.6 |
38.3 |
|
(% of GDP) |
41.1 |
40.4 |
42.4 |
42.4 |
|
(million euro) |
24 776 |
23 813 |
23 080 |
21 823 |
|
(% of GDP) |
96.5 |
80.3 |
71.1 |
62.8 |
|
(million euro) |
364 |
355 |
343 |
327 |
|
(% of GDP) |
1.4 |
1.2 |
1.1 |
0.9 |
|
|
|
|
|
|
|
(million euro) |
32 284 |
36 089 |
39 564 |
40 359 |
|
(million euro) |
-2 331 |
-1 754 |
-934 |
-732 |
|
(% of GDP) |
-7.2 |
-4.9 |
-2.4 |
-1.8 |
|
(% of GDP) |
46.5 |
44.2 |
43.4 |
45.6 |
|
(% of GDP) |
39.3 |
39.4 |
41.1 |
43.8 |
|
(million euro) |
14 810 |
16 039 |
17 579 |
18 801 |
|
(% of GDP) |
45.9 |
44.4 |
44.4 |
46.6 |
|
(million euro) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
56 709 |
67 081 |
74 317 |
78 996 |
|
(million euro) |
-652 |
-482 |
-493 |
-1 012 |
|
(% of GDP) |
-1.1 |
-0.7 |
-0.7 |
-1.3 |
|
(% of GDP) |
37.3 |
36.5 |
37.2 |
39.4 |
|
(% of GDP) |
36.2 |
35.8 |
36.5 |
38.1 |
|
(million euro) |
24 570 |
25 703 |
27 581 |
29 992 |
|
(% of GDP) |
43.3 |
38.3 |
37.1 |
38.0 |
|
(million euro) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
73 039 |
76 731 |
82 115 |
86 180 |
|
(million euro) |
814 |
164 |
-538 |
766 |
|
(% of GDP) |
1.1 |
0.2 |
-0.7 |
0.9 |
|
(% of GDP) |
42.4 |
44.3 |
46.4 |
46.8 |
|
(% of GDP) |
43.5 |
44.5 |
45.7 |
47.7 |
|
(million euro) |
17 664 |
19 107 |
20 268 |
22 649 |
|
(% of GDP) |
24.2 |
24.9 |
24.7 |
26.3 |
|
(million euro) |
667 |
656 |
640 |
619 |
|
(% of GDP) |
0.9 |
0.9 |
0.8 |
0.7 |
|
|
|
|
|
|
|
(million HUF) |
55 560 466 |
65 950 424 |
75 292 668 |
81 447 664 |
|
(million HUF) |
-3 950 388 |
-4 082 786 |
-5 098 959 |
-4 089 556 |
|
(% of GDP) |
-7.1 |
-6.2 |
-6.8 |
-5.0 |
|
(% of GDP) |
48.1 |
49.0 |
49.5 |
47.1 |
|
(% of GDP) |
41.0 |
42.8 |
42.7 |
42.1 |
|
(million HUF) |
42 345 225 |
48 856 449 |
55 139 767 |
59 879 002 |
|
(% of GDP) |
76.2 |
74.1 |
73.2 |
73.5 |
|
(million HUF) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
16 690 |
17 975 |
20 911 |
23 071 |
|
(million euro) |
-1 161 |
-959 |
-927 |
-812 |
|
(% of GDP) |
-7.0 |
-5.3 |
-4.4 |
-3.5 |
|
(% of GDP) |
39.4 |
38.4 |
35.8 |
37.5 |
|
(% of GDP) |
32.5 |
33.1 |
31.4 |
34.0 |
|
(million euro) |
8 305 |
9 048 |
9 826 |
10 647 |
|
(% of GDP) |
49.8 |
50.3 |
47.0 |
46.2 |
|
(million euro) |
227 |
223 |
218 |
210 |
|
(% of GDP) |
1.4 |
1.2 |
1.0 |
0.9 |
|
|
|
|
|
|
|
(million euro) |
891 550 |
993 820 |
1 050 133 |
1 122 459 |
|
(million euro) |
-20 145 |
22 |
-3 897 |
-10 606 |
|
(% of GDP) |
-2.3 |
0.0 |
-0.4 |
-0.9 |
|
(% of GDP) |
45.9 |
43.3 |
44.0 |
44.4 |
|
(% of GDP) |
43.6 |
43.3 |
43.6 |
43.5 |
|
(million euro) |
450 239 |
481 145 |
481 481 |
491 055 |
|
(% of GDP) |
50.5 |
48.4 |
45.8 |
43.7 |
|
(million euro) |
14 345 |
14 086 |
13 740 |
13 850 |
|
(% of GDP) |
1.6 |
1.4 |
1.3 |
1.2 |
|
|
|
|
|
|
|
(million euro) |
406 231 |
449 382 |
477 837 |
494 088 |
|
(million euro) |
-23 129 |
-15 325 |
-12 377 |
-23 106 |
|
(% of GDP) |
-5.7 |
-3.4 |
-2.6 |
-4.7 |
|
(% of GDP) |
56.0 |
53.0 |
52.2 |
55.2 |
|
(% of GDP) |
50.3 |
49.6 |
49.6 |
50.5 |
|
(million euro) |
334 731 |
351 150 |
371 540 |
394 792 |
|
(% of GDP) |
82.4 |
78.1 |
77.8 |
79.9 |
|
(million euro) |
6 984 |
6 858 |
6 689 |
6 451 |
|
(% of GDP) |
1.7 |
1.5 |
1.4 |
1.3 |
|
|
|
|
|
|
|
(million PLN) |
2 661 518 |
3 100 850 |
3 415 274 |
3 653 432 |
|
(million PLN) |
-44 597 |
-104 475 |
-177 442 |
-236 562 |
|
(% of GDP) |
-1.7 |
-3.4 |
-5.2 |
-6.5 |
|
(% of GDP) |
43.6 |
43.2 |
46.9 |
49.4 |
|
(% of GDP) |
41.9 |
39.9 |
41.7 |
43.0 |
|
(million PLN) |
1 410 966 |
1 512 812 |
1 691 261 |
2 012 640 |
|
(% of GDP) |
53.0 |
48.8 |
49.5 |
55.1 |
|
(million PLN) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
216 494 |
243 957 |
270 353 |
289 428 |
|
(million euro) |
-6 117 |
-757 |
3 399 |
1 451 |
|
(% of GDP) |
-2.8 |
-0.3 |
1.3 |
0.5 |
|
(% of GDP) |
47.3 |
43.9 |
41.9 |
42.6 |
|
(% of GDP) |
44.5 |
43.6 |
43.2 |
43.1 |
|
(million euro) |
268 189 |
271 358 |
261 864 |
270 881 |
|
(% of GDP) |
123.9 |
111.2 |
96.9 |
93.6 |
|
(million euro) |
1 054 |
953 |
852 |
701 |
|
(% of GDP) |
0.5 |
0.4 |
0.3 |
0.2 |
|
|
|
|
|
|
|
(million RON) |
1 186 015 |
1 384 598 |
1 590 749 |
1 759 183 |
|
(million RON) |
-85 177 |
-90 338 |
-106 658 |
-164 460 |
|
(% of GDP) |
-7.2 |
-6.5 |
-6.7 |
-9.3 |
|
(% of GDP) |
40.0 |
40.9 |
41.1 |
43.6 |
|
(% of GDP) |
32.8 |
34.4 |
34.4 |
34.2 |
|
(million RON) |
576 339 |
665 491 |
784 235 |
964 808 |
|
(% of GDP) |
48.6 |
48.1 |
49.3 |
54.8 |
|
(million RON) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
|
|
|
|
|
|
|
(million euro) |
52 032 |
56 882 |
64 050 |
67 418 |
|
(million euro) |
-2 399 |
-1 714 |
-1 655 |
-637 |
|
(% of GDP) |
-4.6 |
-3.0 |
-2.6 |
-0.9 |
|
(% of GDP) |
49.9 |
47.7 |
46.5 |
46.5 |
|
(% of GDP) |
45.3 |
44.7 |
44.0 |
45.5 |
|
(million euro) |
38 929 |
41 395 |
43 739 |
44 905 |
|
(% of GDP) |
74.8 |
72.8 |
68.3 |
66.6 |
|
(million euro) |
1 182 |
1 161 |
1 133 |
1 092 |
|
(% of GDP) |
2.3 |
2.0 |
1.8 |
1.6 |
|
|
|
|
|
|
|
(million euro) |
101 892 |
109 960 |
123 539 |
130 208 |
|
(million euro) |
-5 186 |
-1 720 |
-6 542 |
-7 157 |
|
(% of GDP) |
-5.1 |
-1.6 |
-5.3 |
-5.5 |
|
(% of GDP) |
44.8 |
43.1 |
48.2 |
47.5 |
|
(% of GDP) |
39.8 |
41.5 |
42.9 |
42.0 |
|
(million euro) |
61 356 |
63 509 |
68 882 |
77 735 |
|
(% of GDP) |
60.2 |
57.8 |
55.8 |
59.7 |
|
(million euro) |
1 967 |
1 978 |
1 973 |
1 971 |
|
(% of GDP) |
1.9 |
1.8 |
1.6 |
1.5 |
|
|
|
|
|
|
|
(million euro) |
248 764 |
266 135 |
272 848 |
275 963 |
|
(million euro) |
-6 598 |
-477 |
-7 900 |
-12 156 |
|
(% of GDP) |
-2.7 |
-0.2 |
-2.9 |
-4.4 |
|
(% of GDP) |
55.1 |
52.6 |
56.0 |
57.8 |
|
(% of GDP) |
52.5 |
52.5 |
53.1 |
53.4 |
|
(million euro) |
181 911 |
196 844 |
210 321 |
227 547 |
|
(% of GDP) |
73.1 |
74.0 |
77.1 |
82.5 |
|
(million euro) |
4 510 |
4 429 |
4 320 |
4 166 |
|
(% of GDP) |
1.8 |
1.7 |
1.6 |
1.5 |
|
|
|
|
|
|
|
(million SEK) |
5 417 760 |
5 816 415 |
6 143 187 |
6 379 843 |
|
(million SEK) |
-11 073 |
57 635 |
-54 898 |
-100 082 |
|
(% of GDP) |
-0.2 |
1.0 |
-0.9 |
-1.6 |
|
(% of GDP) |
50.4 |
49.4 |
50.0 |
50.7 |
|
(% of GDP) |
50.2 |
50.4 |
49.1 |
49.2 |
|
(million SEK) |
2 017 685 |
1 985 572 |
1 965 761 |
2 171 898 |
|
(% of GDP) |
37.2 |
34.1 |
32.0 |
34.0 |
|
(million SEK) |
0 |
0 |
0 |
0 |
|
(% of GDP) |
0.0 |
0.0 |
0.0 |
0.0 |
Notes for users
Revisions and timetable
In the previous provision of data for the excessive deficit procedure, the 2024 government deficit for the euro area was 3.1% of GDP, for the EU it was 3.2%, and the government debt was 87.4% of GDP for the euro area and 81.0% for the EU. See News release of 22 April 2025.
Methods and definitions
According to Article 14 (1) of Council Regulation (EC) 479/2009, Eurostat publishes the actual government deficit and debt data for the application of the Protocol on the excessive deficit procedure, within three weeks after the reporting deadlines.
The Protocol on the excessive deficit procedure annexed to the EC Treaty, defines government deficit (surplus) as the net borrowing (net lending) of the whole general government sector (central government, state government, local government and social security funds). It is calculated according to national accounts concepts (European System of Accounts, ESA 2010). Government debt (commonly known as Maastricht or EDP debt) is the consolidated gross debt of the whole general government sector outstanding at the end of the year (at nominal value).
– for deficit / surplus and GDP data, the annual average exchange rate;
– for the stock of government debt, the end of year exchange rate.
General government total expenditure and revenue are reported to Eurostat under the ESA 2010 transmission programme. They cover non-financial transactions of general government, and include both current and capital transactions. For definitions, see Regulation (EU) No 549/2013 of the European Parliament and of the Council of 21 May 2013 on the European system of national and regional accounts in the European Union.
Intergovernmental lending
For the purpose of consolidation of general government debt in European aggregates and to provide users with information, Eurostat is collecting and publishing data on government loans to other EU governments, including those made through the European Financial Stability Facility (EFSF). For the years 2021 to 2024 the intergovernmental lending figures relate mainly to lending to Greece, Ireland and Portugal.
Reservations and amendments
The term “reservations” is defined in article 15 (1) of Council Regulation (EC) 479/2009. The Commission (Eurostat) expresses reservations when it has doubts on the quality of the reported data.
According to Article 15 (2) of Council Regulation (EC) 479/2009, the Commission (Eurostat) may amend actual data reported by Member States and provide the amended data and a justification of the amendment where there is evidence that actual data reported by Member States do not comply with the quality requirements (compliance with accounting rules, completeness, reliability, timeliness and consistency of statistical data).
Geographical information
Euro area (EA20): Belgium, Germany, Estonia, Ireland, Greece, Spain, France, Croatia, Italy, Cyprus, Latvia, Lithuania, Luxembourg, Malta, Netherlands, Austria, Portugal, Slovenia, Slovakia and Finland.
European Union (EU27): Belgium, Bulgaria, Czechia, Denmark, Germany, Estonia, Ireland, Greece, Spain, France, Croatia, Italy, Cyprus, Latvia, Lithuania, Luxembourg, Hungary, Malta, the Netherlands, Austria, Poland, Portugal, Romania, Slovenia, Slovakia, Finland and Sweden.
For more information
For further information on the methodology of statistics reported under the excessive deficit procedure, please see the Eurostat publication “Manual on Government Deficit and Debt – Implementation of ESA 2010 – 2022 edition”, published in February 2023.
Note on main revisions: Eurostat publishes on its website a note containing specific explanations of the largest revisions in deficit and debt for 2021-2024 between the April and October 2025 notifications, as well as in GDP.
Background note and supplementary tables on government interventions to support financial institutions: Eurostat publishes supplementary tables by Member State on the impact of the government support to financial institutions on its website. Eurostat also publishes a background note providing further information on the supplementary tables, including summary tables for the EU and the euro area. Table 2 of the background note shows government deficit/surplus data for 2023 and 2024 excluding the impacts of government interventions to support financial institutions. It should be noted that this adjusted measure of government deficit/surplus is only intended to be an improvement in the presentation of data for users.
Stock of liabilities of trade credits and advances: Eurostat publishes on its website, as complementary information on government liabilities, data on trade credits and advances, as reported by Member States for the years 2021 to 2024. According to Council Regulation (EC) 479/2009, the liabilities in trade credits and advances of government units are not part of EDP debt.
Stock-flow adjustment: Eurostat also publishes a note on the stock-flow adjustment which presents the contribution of deficit/surplus as well as other relevant factors to the variation in the debt level.
Eurostat will also be releasing information on the underlying government sector accounts on the government finance and EDP statistics section on its website.
Share the release
Share component will be rendered here.
* Here the title * … *
… * * Here the logo and notes * */ function tableConfiguration() { /** Retrieves the list of table elements (images) */ const tables = document.getElementsByTagName(‘table’); /** We go through the list of tables */ for (let table of tables) { /** We create a section to wrap the table */ let section = document.createElement(‘section’); /** Add table-wrapper class to section element */ section.classList.add(‘table-wrapper’); /** We create a caption element to place the title */ let caption = document.createElement(‘caption’); /** We create thead element to place the headers */ let tHead = document.createElement(‘thead’); /** We create a footer to place notes, datasource and logo */ let footer = document.createElement(‘footer’); /** Retrieves the tBody */ let tBody = table.tBodies[0]; /** Retrieves the table rows */ let rows = tBody.rows; let datalabels = []; let captionContent = []; /** Stores the indexes of the rows to be removed after processing the whole table */ let rowsToRemove = []; /** We go through the rows within the table and extract caption, headers and footnotes */ buildTable(rows, captionContent, datalabels, footer, rowsToRemove); deleteRows(table, rowsToRemove); addTableCaption(caption, captionContent); addTableHeaders(table, tHead, datalabels); wrapInSection(section, table, caption, tHead, tBody, footer); linkHeaders(table); } } /** * Builds a table with the expected format: adding caption, datalabels and footer * @param {*} rows – The table rows * @param {*} captionContent – The content of the caption (title) * @param {*} datalabels – The list of datalabels (table headers) * @param {*} footer – The footer element * @param {*} rowsToRemove – Array containing the index of the rows to be removed */ function buildTable(rows, captionContent, datalabels, footer, rowsToRemove) { let rowIndex = 0; for (let row of rows) { let cells = row.cells; /** We check the first cell in order to guess the cell type: th, td; and cell classes: title, datalabel… */ let firstCell = row.firstElementChild; /** If the th class name is title, we convert this th into a caption */ if (isCaption(firstCell)) { addCaption(cells, captionContent, rowIndex, rowsToRemove) } /** If the th class name is datalabel, we add the header to the tHead component */ else if (isDatalabel(firstCell)) { addDatalabels(row, datalabels, rowIndex, rowsToRemove); } /** If the th class name is title, we convert this th into a caption */ else if (isFooter(firstCell)) { addFooter(row, footer, rowIndex, rowsToRemove); } else { row.setAttribute(‘initial-position’, rowIndex); } rowIndex++; } } /** * Checks whether the given cell has the given tagName and className * @param {*} cell – The cell to be checked * @param {*} tagName – The tag name to be checked * @param {*} className – The class name to be checked * @returns true if the cell’s tagName and className matches the given ones, false otherwise */ function checkCell(cell, tagName, className) { return cell.tagName.toLowerCase() === tagName && cell.className.indexOf(className) > -1; } /** * Whether a cell is a caption (title) * @param {*} cell – The cell to be checked * @returns true if the cell is a caption, false otherwise */ function isCaption(cell) { return checkCell(cell, ‘th’, ‘title’); } /** * Whether a cell is a datalabel * @param {*} cell – The cell to be checked * @returns true if the cell is a datalabel, false otherwise */ function isDatalabel(cell) { return checkCell(cell, ‘th’, ‘datalabel’); } /** * Whether a cell is a vertical header * @param {*} cell – The cell to be checked * @returns true if the cell is a vertical header, false otherwise */ function isVerticalHeader(cell) { return checkCell(cell, ‘th’, ‘vertical-header’); } /** * Whether a cell is a footer * @param {*} cell – The cell to be checked * @returns true if the cell is a footer, false otherwise */ function isFooter(cell) { return checkCell(cell, ‘td’, ‘footer’); } /** * Adds the content of the caption cells: paragraphs * @param {*} cells – The cells belonging to the row * @param {*} captionContent – The content of the caption * @param {*} rowIndex – The index of current row * @param {*} rowsToRemove – Array containing the index of the rows to be removed */ function addCaption(cells, captionContent, rowIndex, rowsToRemove) { for (let cell of cells) { /** We must add all the Child Nodes of each th title Cell */ for (let childNode of cell.childNodes) { captionContent.push(childNode); } } /** We remove the row from within the tables as now it’s out in the caption */ rowsToRemove.push(rowIndex); } /** * Adds the row as a datalabel * @param {*} row – The current row * @param {*} datalabels – List of datalabels * @param {*} rowIndex – The index of current row * @param {*} rowsToRemove – Array containing the index of the rows to be removed */ function addDatalabels(row, datalabels, rowIndex, rowsToRemove) { datalabels.push(row); /** We remove the row from within the tables as now it’s out in the caption */ rowsToRemove.push(rowIndex); } /** * Adds the notes and logo * @param {*} row – The current row * @param {*} footer – The footer of the table * @param {*} rowIndex – The index of current row * @param {*} rowsToRemove – Array containing the index of the rows to be removed */ function addFooter(row, footer, rowIndex, rowsToRemove) { /** We create a div element for notes and logo */ const notes = document.createElement(‘div’); notes.classList.add(‘footer-element’, ‘notes’); /** We add the content to the new note element */ notes.innerHTML = row.firstElementChild.innerHTML; /** We create a footer to place notes, datasource and logo */ footer.appendChild(notes); /** We remove the row from within the tables as now it’s out in the footer */ rowsToRemove.push(rowIndex); } /** * Deletes the rows which data has been moved to either caption, tHead or footer * @param {*} table – The current table * @param {*} rowsToRemove – Array containing the index of the rows to be removed */ function deleteRows(table, rowsToRemove) { /** We go through the title rows and append them to the caption element */ for (let j = rowsToRemove.length – 1; j >= 0; j–) { table.deleteRow(rowsToRemove[j]); } } /** * Adds the caption to the table. * @param {*} caption – The caption dom element * @param {*} captionContent – The content of the caption */ function addTableCaption(caption, captionContent) { /** We go through the Caption Content and append the nodes to the caption element */ for (let node of captionContent) { caption.appendChild(node); } } /** * Adds the headers to the table * @param {*} table – The table to make sortable * @param {*} tHead – The thead dom element * @param {*} datalabels – The datalabels to be added (headers) */ function addTableHeaders(table, tHead, dataLabels) { let sortable = false; /** We go through the header rows and append them to the tHead element */ for (let dataLabelRow of dataLabels) { let cells = dataLabelRow.cells; for (let th of cells) { if (th.classList.contains(‘sortable’)) { sortable = true; let button = createNewSortButton(); th.appendChild(button); } } tHead.appendChild(dataLabelRow); } if (sortable) { table.classList.add(‘sortable’); } } function createNewSortButton() { // creates sort button const button = document.createElement(‘button’); button.classList.add(‘ecl-table__arrow’); // creates a generic svg element for the two arrows const svgIconUp = document.createElementNS(‘http://www.w3.org/2000/svg’, ‘svg’); svgIconUp.setAttribute(‘xml:space’, ‘preserve’); svgIconUp.setAttribute(‘viewBox’, ‘0 0 24 24’); svgIconUp.setAttribute(‘enable-background’, ‘new 0 0 24 24’); svgIconUp.setAttribute(‘focusable’, ‘false’); svgIconUp.setAttribute(‘aria-hidden’, ‘true’); svgIconUp.setAttribute(‘class’, ‘ecl-table__icon ecl-icon ecl-icon–m’); // adds path element of the arrow to the arrow svg const pathIconArrow = document.createElementNS(‘http://www.w3.org/2000/svg’, ‘path’); pathIconArrow.setAttribute(‘d’, ‘M7.4 13 11 9.4c.5-.5 1.4-.5 2 0l3.6 3.6c.9.9.2 2.4-1 2.4H8.4c-1.3 0-1.9-1.5-1-2.4’); svgIconUp.appendChild(pathIconArrow); // clones the generic arrow svg including the child path also const svgIconDown = svgIconUp.cloneNode(true); // seups the arrow directions to up and down by extra css classes svgIconUp.classList.add(‘ecl-table__icon-up’); svgIconDown.classList.add(‘ecl-table__icon-down’); // insert the two arrow svg elements into the button button.appendChild(svgIconUp); button.appendChild(svgIconDown); return button; } /** * Places all the elements in their places and wraps the table into a section. * @param {*} section – The section (dom element) which will wrap table and footer * @param {*} table – The table to be wrapped * @param {*} caption – The caption (dom element) to be added to the table * @param {*} tHead – The thead (dom element) to be added to the table * @param {*} tBody – The tbody (dom element) to be added to the table * @param {*} footer – The footer (dom element) to be added to the section */ function wrapInSection(section, table, caption, tHead, tBody, footer) { /** We insert caption and thead before tbody */ table.insertBefore(caption, tBody); table.insertBefore(tHead, tBody); /** We wrap the table into a section */ table.parentNode.insertBefore(section, table); section.appendChild(table); section.appendChild(footer); } /** * Adds ids and header attributes to link every cell to all related headers so that machines can correctly read the figures. * @param {*} table – The table to be wrapped */ function linkHeaders(table) { const headers = getHeaders(table.tHead); const tBody = table.tBodies ? table.tBodies[0] : null; addHeaderLinks(tBody, headers); } function getHeaders(tHead) { const headers = []; if (tHead) { let i = 0; for (let row of tHead.rows) { /** We add a new row in the headers array */ headers.push([]); /** Stores the header ids and colSpan so we can guess to which cells (td) we must add the headers */ let j = 0; for (const cell of row.cells) { cell.setAttribute(‘id’, ‘h_’ + i + ‘_’ + j); headers[i].push({ id: cell.id, colSpan: cell.colSpan ? cell.colSpan : 1 }); j++; } i++; } } return headers; } function addHeaderLinks(tBody, headers) { if (tBody) { let i = 0; for (let row of tBody.rows) { let j = 0; for (const cell of row.cells) { /** If the cell is a vertical header we add its id */ if (cell.className.indexOf(‘vertical-header’) > -1) { cell.setAttribute(‘id’, ‘vh_’ + i + ‘_’ + j); } const headerLinks = getHeaderLinks(headers, j, cell.colSpan, row.cells[0]); cell.setAttribute(‘headers’, headerLinks); j++; } i++; } } } /** * Retrieves the header (ths) ids in order to link them to a specific cell (td) * @param {*} rows – The rows containing all headers * @param {*} index – The index of the specific cell * @param {*} colSpan – The colspan of the specific cell * @param {*} firstCell – The first cell of the row. Used to reference possible vertical headers * @returns A string containing the list of header ids split by spaces */ function getHeaderLinks(rows, index, colSpan, firstCell) { /** It will contain the header ids */ let links = ”; /** We add the reference of the vertical header if there is */ if (index > 0 && firstCell.className.indexOf(‘vertical-header’) > -1) { links = firstCell.id; } /** We go through the list of header rows */ for (const headers of rows) { /** Accumulates the colspan of the checked headers */ let sumColSpan = 0; /** We go through the list of headers for the specific header row */ for (const header of headers) { /** We check that the index of the cell belongs to a specific column */ if (index >= sumColSpan && index chartObj.resize()).observe(chartDiv); } } /** * Customizes the chart by applying custom events, axis formats, tooltips, and axis labels. * @param option – The chart options object. */ function customChartOptions(option) { setClickableDatasourceLinks(option); setAxisFormatter(option); setTooltipFormatter(option); } /** * Attaches event handlers to a chart: ‘legendselectchanged’. * * @param {Chart} chart – The chart object. */ function addEventHandlers(chart) { /** Attach an event handler for the ‘legendselectchanged’ event */ chart.on(‘legendselectchanged’, (event) => { /** Call the onChartLegendSelected function with the event and chart object */ onChartLegendSelected(event, chart); }); } /** * Handles the legend selected changed event of the chart. * @param {any} event – The event object containing the selected legend items. * @param {any} chart – The chart object. */ function onChartLegendSelected(event, chart) { /** Get the selected legend items */ const selected = event.selected; /** Count the number of selected legend items */ const selectedCount = Object.values(selected).filter(Boolean).length; /** If all legend items are deselected, keep the selection on the last clicked item */ if (selectedCount === 0) { selected[event.name] = true; } /** Update the legend selection */ chart.setOption({ legend: { selected: selected } }); } /** * Attaches custom events to the provided option object. * * @param {object} option – The option object to attach custom events to. */ function setClickableDatasourceLinks(option) { /** If the table has datasource link */ if (option.graphic && option.graphic.length >= 3) { /** Attach an onclick event handler to the third element of the graphic array (datasource links) */ option.graphic[2].onclick = function (event) { /** If the element has a link defined in its style */ if (this.style?.link) { /** Open the link in a new tab/window */ window.open(this.style.link, ‘_blank’); } }; } } /** * Sets the default axis formatter for axis labels. * @param {object} option – The option object to update the axis formatter * */ function setAxisFormatter(option) { /** The default unit used in axis labels */ const defaultUnit = ‘%’; /** If the yAxis are used as values */ if (option.yAxis.type === ‘value’) { /** If the yAxis unit is not defined, set % as default */ option.yAxis.axisLabel.unit = option.yAxis.axisLabel.unit ? option.yAxis.axisLabel.unit : defaultUnit; /** If the yAxis label padding is not defined, set 15 as default suffix */ option.yAxis.axisLabel.padding = option.yAxis?.axisLabel?.padding ? option.yAxis.axisLabel.padding : 15; /** Use the custom formatter */ option.yAxis.axisLabel.formatter = (value) => customAxisFormatter(option.lang, value, option.yAxis.axisLabel.unit, parseInt(option.yAxis.axisLabel.decimals)); // Use the custom formatter } /** If the xAxis are used as values */ if (option.xAxis.type === ‘value’) { /** If the xAxis unit is not defined, set % as default */ option.xAxis.axisLabel.unit = option.xAxis.axisLabel.unit ? option.xAxis.axisLabel.unit : defaultUnit; /** Use the custom formatter */ option.xAxis.axisLabel.formatter = (value) => customAxisFormatter(option.lang, value, option.xAxis.axisLabel.unit, parseInt(option.xAxis.axisLabel.decimals)); } /** If xAxis type is category */ else if (option.xAxis.type === ‘category’) { richStyle(option); } } /** * Formats a numeric value with a specified unit and decimal precision. * * @param {number} value – The numeric value to be formatted. * @param {string} unit – The unit to be appended to the formatted value. * @param {number} decimals – The number of decimal places to round the value to. * @returns {string} The formatted string representation of the value with unit. */ function customAxisFormatter(lang, value, unit, decimals) { /** * Check the language and format the value accordingly. * For French (fr) and German (de), use commas instead of dots. * For other languages (en), use the default format with dots. */ const formattedValue = lang === ‘fr’ || lang === ‘de’ ? `${value.toFixed(decimals).replace(‘.’, ‘,’)}${unit}` : `${value.toFixed(decimals)}${unit}`; return formattedValue; } /** * Applies custom rich text formatting to axis labels based on certain string patterns and HTML tags. * * Checks if the axis label contains certain values such as “EU”, “Euro Area”, and specific HTML tags. * It formats the labels by applying bold or italic styles as needed. * * @param axis – The axis object to which the formatting will be applied. * @returns The updated axis object with the formatted axis label. */ function richStyle(option) { /** Regular expression to match HTML tags like and */ const htmlTagRegex = /(.*?)/g; /** Mapping of HTML tags to corresponding rich text formatting styles */ const style = { strong: “bold”, em: “italic” }; /** * Formatter function for axis labels. * Converts specific label values into rich text format (e.g., bold). * * @param value – The value of the axis label to be formatted. * @returns The formatted axis label. */ option.xAxis.axisLabel.formatter = function (value) { /** Convert input string to lowercase for case-insensitive comparison */ const lowerCaseV = value ? value.toLowerCase() : ”; /** Check for “EU”, “UE”, “Euro Area”, “Euroraum” or “Zone Euro” and format them as bold */ if (lowerCaseV === ‘eu’ || lowerCaseV === ‘ue’ || lowerCaseV === ‘euro area’ || lowerCaseV === ‘euroraum’ || lowerCaseV === ‘zone euro’) { return `{bold|${value}}`; } /** Strictly check if the string contains supported HTML tags before formatting */ if (htmlTagRegex.test(value)) { /** Replace HTML tags with corresponding rich text formatting */ return value.replace(htmlTagRegex, (match, tag, content) => { return `{${style[tag]}|${content}}`; }); } /** Return the value as is if no formatting is needed */ return value; }; /** * Define the rich text styles for the axis labels. * These styles will be applied to specific HTML tags detected in the formatter function. */ option.xAxis.axisLabel.rich = { bold: { fontWeight: ‘bold’ }, italic: { fontStyle: ‘italic’ } }; } /** * Handles formatting the tooltip decimal convention in the graphic. * @remarks * This function formats the tooltip based on the language and decimal convention. * * @param {object} option – The option object to add custom tooltip. */ function setTooltipFormatter(option) { /** * Tooltip formatter for ECharts. * @param {object[]} params – Parameters for the tooltip formatter. * @param {string} params[].name – Name of the x-axis value. * @param {string} params[].seriesName – Name of the series. * @param {number} params[].value – Value of the data point. * @param {string} params[].color – Color of the series. * @param {string} ticket – Ticket for the callback. * @param {Function} callback – Callback function. * @returns {string} – Formatted tooltip content. */ option.tooltip.formatter = function (params, ticket, callback) { /** Retrieve the x-axis value for the tooltip */ const xAxisValue = params[0].name; /** If xAxisValue is empty, return null to hide the tooltip */ if (!xAxisValue) { return null; } /** Create the tooltip content container with a white background and padding */ let tooltipContent = ”; /** Add the x-axis value to the tooltip content */ /** @type {string} XAxis */ tooltipContent += ” + xAxisValue + ‘]]>‘; /** Retrieve the order from the tooltip option */ const sortOrder = option.tooltip.order; /** Sort the ‘params’ array based on the ‘sortOrder’ parameter. */ switch (sortOrder) { /** Sort by series name in ascending order. */ case ‘seriesAsc’: params = params.sort((a, b) => a.seriesName.localeCompare(b.seriesName)); break; /** Sort by series name in descending order. */ case ‘seriesDesc’: params = params.sort((a, b) => b.seriesName.localeCompare(a.seriesName)); break; /** Sort by numerical value in ascending order. */ case ‘valueAsc’: params = params.sort((a, b) => parseFloat(a.value) – parseFloat(b.value)); break; /** Sort by numerical value in descending order. */ case ‘valueDesc’: params = params.sort((a, b) => parseFloat(b.value) – parseFloat(a.value)); break; /** Reverse the current order. */ case ‘reverse’: params.reverse(); break; default: break; } /** Iterate over each series in the tooltip parameters */ for (const param of params) { /** Retrieve the name and value of the current series */ let seriesName = param.seriesName; let value = param.value; /** Replace every specific apostrphe by simple one. */ seriesName = seriesName.replaceAll(“’”, “‘”); /** Convert the numeric value to its string representation. */ const strValue = String(value); /** Retrieve the axis used as value */ const axis = option.yAxis.type === ‘value’ ? option.yAxis : option.xAxis; /** Initialize the number of decimal places */ let decimals = option.tooltip.decimals; /** Check if decimals configuration is set to default and the value contains decimal places */ if (!decimals && strValue.indexOf(‘.’) > -1) { /** Calculate the number of decimal places */ decimals = strValue.substring(strValue.indexOf(‘.’), strValue.length – 1).length; } else { /** If there are no decimal places, format the value with 1 decimal place */ decimals = decimals || 1; /** Convert the value to a fixed-point notation string with a specified number of decimal places. */ value = Number(value).toFixed(decimals); } /** Convert -0 value to 0 with the specified or calculated number of decimal places.*/ if (Number(value) == -0) { value = (Number(value) + 0).toFixed(decimals); } /** Extract the unit from within the axis label */ const unit = axis.axisLabel.unit ? axis.axisLabel.unit : ”; /** Format the value using the appropriate number of decimal places */ if (isNaN(value)) { value = ‘N/A’; } else { value = Number(value).toLocaleString(option.lang ? option.lang : ‘en’, { minimumFractionDigits: decimals }) + unit; } /** Retrieve the color of the current series */ const color = param.color; /** * Add the series name and value to the tooltip content * Use a circle icon with the series color */ tooltipContent += ‘
‘ + ” + ” + ” + seriesName + ” + ” + ” + value + ” + ‘
‘; } /** Close the tooltip content container */ tooltipContent += ”; /** Return the formatted tooltip content */ return tooltipContent; } } /* * This content is licensed according to the W3C Software License at * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * * File: sortable-table.js * * Desc: Adds sorting to a HTML data table that implements ARIA Authoring Practices */ class SortableTable { constructor(tableNode) { this.tableNode = tableNode; this.columnHeaders = tableNode.querySelectorAll(‘thead th.sortable’); this.sortColumns = []; for (let i = 0; i b.value ? -1 : 1; } } else if (isNumber) { return a.value – b.value; } else { return a.value
Subscribe to receive the latest Eurostat Euro indicators releases
{ if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } waitForElm(‘div.chart’).then((elm) => { // Has to be run after cool-ngx-editor.js script that is tweeking the charts const elements = document.getElementsByClassName(“chart”); for (let i = 0; i < elements.length; i++) { let div = document.createElement('div'); div.id = "share-chart-" + i; div.style = "position: absolute; right: 0; z-index: 50;"; elements[i].prepend(div); let script = document.createElement('script'); script.type = "application/json"; let url = new URL(window.location.href); url.searchParams.set('item', 'chart'); url.searchParams.set('id', i); let code = '{"service": "sbkm", "version": "2.0", "popup": false, "icon": true, "more" : ["facebook", "x", "linkedin", "email"], "renderTo": "' + div.id + '", "to": ["more"], "target": true, "link": "' + url.href + '", "via": "EU_Eurostat", "title": "' + getJournalArticleTitle() + '"}'; try { script.appendChild(document.createTextNode(code)); } catch (e) { // Older browsers may not support appendChild(document.createTextNode(...)) on . // Fallback to setting text directly on the script element. console.warn('Failed to append text node to script element, falling back to setting text', e); script.text = code; } elements[i].parentNode.insertBefore(script, elements[i].nextSibling); } }); // Add share button to tables $(document).ready(function() { // Has to be run after cool-ngx-editor.js script that is tweeking the tables const tables = document.getElementsByTagName("table"); for (let i = 0; i position) { await new Promise(r => setTimeout(r, 500)); // Wait a bit so that it doesn’t scroll too far allItems[position].scrollIntoView(true); } } });;}());]]>
