gov-uk-dashboards 16.1.0__tar.gz → 17.0.0__tar.gz

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 (118) hide show
  1. {gov_uk_dashboards-16.1.0/gov_uk_dashboards.egg-info → gov_uk_dashboards-17.0.0}/PKG-INFO +1 -1
  2. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/__init__.py +0 -1
  3. gov_uk_dashboards-17.0.0/gov_uk_dashboards/components/dash/download_button.py +66 -0
  4. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/helpers/display_chart_or_table_with_header.py +17 -22
  5. gov_uk_dashboards-17.0.0/gov_uk_dashboards/components/helpers/get_chart_for_download.py +21 -0
  6. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/plotly/stacked_barchart.py +7 -0
  7. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/plotly/time_series_chart.py +23 -0
  8. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/constants.py +6 -0
  9. gov_uk_dashboards-17.0.0/gov_uk_dashboards/lib/download_functions/__init__.py +0 -0
  10. gov_uk_dashboards-17.0.0/gov_uk_dashboards/lib/download_functions/convert_fig_to_image_and_download.py +16 -0
  11. gov_uk_dashboards-17.0.0/gov_uk_dashboards/lib/download_functions/download_csv_with_headers.py +114 -0
  12. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0/gov_uk_dashboards.egg-info}/PKG-INFO +1 -1
  13. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards.egg-info/SOURCES.txt +5 -3
  14. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/setup.py +1 -1
  15. gov_uk_dashboards-16.1.0/gov_uk_dashboards/components/dash/create_download_chart_button.py +0 -25
  16. gov_uk_dashboards-16.1.0/gov_uk_dashboards/components/dash/create_download_data_button.py +0 -25
  17. gov_uk_dashboards-16.1.0/gov_uk_dashboards/components/dash/download_button.py +0 -62
  18. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/LICENSE +0 -0
  19. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/MANIFEST.in +0 -0
  20. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/README.md +0 -0
  21. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/__init__.py +0 -0
  22. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/__init__.py +0 -0
  23. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/attach-event-to-dash.js +0 -0
  24. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/dashboard.css +0 -0
  25. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/fonts/bold-affa96571d-v2.woff +0 -0
  26. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/fonts/bold-b542beb274-v2.woff2 +0 -0
  27. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/fonts/light-94a07e06a1-v2.woff2 +0 -0
  28. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/fonts/light-f591b13f7d-v2.woff +0 -0
  29. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/get_assets_folder.py +0 -0
  30. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/govuk-frontend-3.14.0.min.js +0 -0
  31. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/DLUHC_WHITE_Master_AW_sm.png +0 -0
  32. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/MHCLG-favicon.png +0 -0
  33. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/MHCLG_favicon.png +0 -0
  34. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/dcms_coatofarms.png +0 -0
  35. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/dluhc_favicon.ico +0 -0
  36. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/gov_favicon.ico +0 -0
  37. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/govuk-crest.svg +0 -0
  38. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/hm-government-logo.png +0 -0
  39. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/mhclg_coat_of_arms.png +0 -0
  40. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/mhclg_white_no_background.png +0 -0
  41. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/oflog/MedianAbsolute.png +0 -0
  42. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/oflog/how_to_1_selecting_data.png +0 -0
  43. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/oflog/how_to_2_viewing_tabs.png +0 -0
  44. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/oflog/how_to_3_viewing_charts.png +0 -0
  45. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/oflog/how_to_4_viewing_trends.png +0 -0
  46. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/images/oflog/how_to_5_viewing_tables.png +0 -0
  47. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/mobile-nav.js +0 -0
  48. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/topojson/usa_110m.json +0 -0
  49. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/assets/topojson/world_110m.json +0 -0
  50. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/axes.py +0 -0
  51. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/colours.py +0 -0
  52. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/__init__.py +0 -0
  53. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/apply_and_reset_filters_buttons.py +0 -0
  54. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/banners.py +0 -0
  55. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/card.py +0 -0
  56. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/card_full_width.py +0 -0
  57. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/collapsible_panel.py +0 -0
  58. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/comparison_la_filter_button.py +0 -0
  59. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/context_banner.py +0 -0
  60. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/dashboard_container.py +0 -0
  61. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/details.py +0 -0
  62. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/filter_panel.py +0 -0
  63. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/footer.py +0 -0
  64. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/graph.py +0 -0
  65. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/header.py +0 -0
  66. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/heading.py +0 -0
  67. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/home_page_link_button.py +0 -0
  68. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/html_list.py +0 -0
  69. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/key_value_pair.py +0 -0
  70. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/main_content.py +0 -0
  71. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/navbar.py +0 -0
  72. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/no_data_message.py +0 -0
  73. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/notification_banner.py +0 -0
  74. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/paragraph.py +0 -0
  75. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/phase_banner.py +0 -0
  76. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/row_component.py +0 -0
  77. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/side_navbar.py +0 -0
  78. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/table.py +0 -0
  79. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/tooltip.py +0 -0
  80. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/tooltip_title.py +0 -0
  81. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/visualisation_commentary.py +0 -0
  82. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/visualisation_title.py +0 -0
  83. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/dash/warning_text.py +0 -0
  84. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/helpers/__init__.py +0 -0
  85. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/helpers/generate_dash_graph_from_figure.py +0 -0
  86. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/helpers/plotting_helper_functions.py +0 -0
  87. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/helpers/update_layout_bgcolor_margin.py +0 -0
  88. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/plotly/__init__.py +0 -0
  89. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/plotly/captioned_figure.py +0 -0
  90. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/plotly/choropleth_map.py +0 -0
  91. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/components/plotly/enums.py +0 -0
  92. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/__init__.py +0 -0
  93. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/chart_data.py +0 -0
  94. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/enums/__init__.py +0 -0
  95. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/enums/dash_patterns.py +0 -0
  96. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/line_chart.py +0 -0
  97. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/styles/__init__.py +0 -0
  98. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/figures/styles/line_style.py +0 -0
  99. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/formatting/__init__.py +0 -0
  100. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/formatting/human_readable.py +0 -0
  101. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/formatting/round_and_add_prefix_and_suffix.py +0 -0
  102. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/formatting/rounding.py +0 -0
  103. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/__init__.py +0 -0
  104. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/dap/__init__.py +0 -0
  105. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/dap/dap_deployment.py +0 -0
  106. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/dap/get_dataframe_from_cds.py +0 -0
  107. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/datetime_functions/__init__.py +0 -0
  108. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/datetime_functions/datetime_functions.py +0 -0
  109. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/enable_basic_auth.py +0 -0
  110. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/http_headers.py +0 -0
  111. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/lib/logging.py +0 -0
  112. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/symbols.py +0 -0
  113. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/template.html +0 -0
  114. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards/template.py +0 -0
  115. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards.egg-info/dependency_links.txt +0 -0
  116. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards.egg-info/requires.txt +0 -0
  117. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/gov_uk_dashboards.egg-info/top_level.txt +0 -0
  118. {gov_uk_dashboards-16.1.0 → gov_uk_dashboards-17.0.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gov_uk_dashboards
3
- Version: 16.1.0
3
+ Version: 17.0.0
4
4
  Summary: Provides access to functionality common to creating a data dashboard.
5
5
  Author: Department for Levelling Up, Housing and Communities
6
6
  Description-Content-Type: text/markdown
@@ -68,7 +68,6 @@ from .card import card, empty_card
68
68
  from .card_full_width import card_full_width
69
69
  from .apply_and_reset_filters_buttons import apply_and_reset_filters_buttons
70
70
  from .download_button import download_button
71
- from .download_button import download_button_with_icon
72
71
  from .collapsible_panel import collapsible_panel
73
72
  from .dashboard_container import dashboard_container
74
73
  from .details import details
@@ -0,0 +1,66 @@
1
+ """download_button"""
2
+ import warnings
3
+ from dash import html
4
+
5
+ from gov_uk_dashboards.constants import DOWNLOAD_BUTTON_CLASSES
6
+
7
+
8
+ def download_button(button_text: str, button_id: str = "download-button"):
9
+ """
10
+ Return a download button which is aligned to the right
11
+
12
+ Args:
13
+ button_text (str): The text to display on the button.
14
+ button_id: (str, Optional) = id for dropdown, default to "download-button"
15
+ """
16
+ warnings.warn(
17
+ "Note there is an alternative function to download_button() called "
18
+ "create_download_button_with_icon() which includes a download icon and improved styling.",
19
+ Warning,
20
+ stacklevel=2,
21
+ )
22
+
23
+ return html.Div(
24
+ [
25
+ html.Button(
26
+ button_text,
27
+ id=button_id,
28
+ n_clicks=0,
29
+ className="govuk-button govuk-button--secondary",
30
+ ),
31
+ ],
32
+ className="govuk-button-group",
33
+ style={"float": "right"},
34
+ )
35
+
36
+
37
+ def create_download_button_with_icon(
38
+ button_text: str, button_id_name: str
39
+ ) -> html.Button:
40
+ """Create a download button with icon, aligned to the left.
41
+
42
+ Parameters:
43
+ - button_id_name (str): A unique identifier for the button.
44
+
45
+ Returns:
46
+ - html.Button: Download button.
47
+ """
48
+ download_type = button_text.lower().replace(" ", "-")
49
+ return html.Button(
50
+ [
51
+ html.Div("", className="download-icon"),
52
+ button_text,
53
+ ],
54
+ id={
55
+ "download-type": download_type,
56
+ "name": button_id_name,
57
+ },
58
+ n_clicks=0,
59
+ className=DOWNLOAD_BUTTON_CLASSES,
60
+ type="submit",
61
+ style={
62
+ "display": "flex",
63
+ "alignItems": "center",
64
+ "gap": "8px",
65
+ },
66
+ )
@@ -3,11 +3,8 @@
3
3
  from dash import html
4
4
  from dash.development.base_component import Component
5
5
 
6
- from gov_uk_dashboards.components.dash.create_download_chart_button import (
7
- create_download_chart_button,
8
- )
9
- from gov_uk_dashboards.components.dash.create_download_data_button import (
10
- create_download_data_button,
6
+ from gov_uk_dashboards.components.dash.download_button import (
7
+ create_download_button_with_icon,
11
8
  )
12
9
  from gov_uk_dashboards.components.dash.heading import HeadingSizes
13
10
 
@@ -36,11 +33,6 @@ def display_chart_or_table_with_header(
36
33
  [
37
34
  html.Div(
38
35
  [
39
- (
40
- create_download_chart_button(button_id_name=download_button_id)
41
- if download_button_id
42
- else None
43
- ),
44
36
  html.Div(
45
37
  [
46
38
  html.H2(
@@ -61,20 +53,23 @@ def display_chart_or_table_with_header(
61
53
  html.Div(
62
54
  (
63
55
  [
64
- html.H3(
65
- "Download this data",
66
- className=HeadingSizes.SMALL,
67
- style={
68
- **{"color": "black", "margin": "0px 0px 5px"},
69
- **{"padding-top": "20px"},
70
- },
71
- ),
72
- create_download_data_button(
73
- button_id_name=download_data_button_id
56
+ html.Div(
57
+ [
58
+ create_download_button_with_icon(
59
+ "Download chart", download_button_id
60
+ )
61
+ if download_button_id
62
+ else [],
63
+ create_download_button_with_icon(
64
+ "Download data", download_data_button_id
65
+ )
66
+ if download_data_button_id
67
+ else [],
68
+ ],
69
+ className="govuk-button-group",
70
+ style={"padding-top": "20px"},
74
71
  ),
75
72
  ]
76
- if download_data_button_id
77
- else []
78
73
  ),
79
74
  ),
80
75
  ],
@@ -0,0 +1,21 @@
1
+ """get_chart_for_download"""
2
+ from gov_uk_dashboards.constants import MAIN_TITLE, SUBTITLE
3
+
4
+
5
+ def get_chart_for_download(self, fig):
6
+ """Returns a fig with title and subtitle for download as png"""
7
+ main_title = self.title_data[MAIN_TITLE]
8
+ subtitle = self.title_data[SUBTITLE]
9
+
10
+ fig.update_layout(
11
+ title={
12
+ "text": f"<b><span style='color: black; margin: 0px 0px 5px'>{main_title}</span></b>",
13
+ "x": 0.01,
14
+ "xanchor": "left",
15
+ },
16
+ title_subtitle={
17
+ "text": f"<b><span style='color: black; margin: 0px 0px 5px'>{subtitle}</span></b>"
18
+ },
19
+ margin={"t": 100},
20
+ )
21
+ return fig
@@ -7,6 +7,9 @@ import polars as pl
7
7
 
8
8
  import plotly.graph_objects as go
9
9
 
10
+ from gov_uk_dashboards.components.helpers.get_chart_for_download import (
11
+ get_chart_for_download,
12
+ )
10
13
  from gov_uk_dashboards.constants import (
11
14
  CHART_LABEL_FONT_SIZE,
12
15
  CUSTOM_DATA,
@@ -117,6 +120,10 @@ class StackedBarChart:
117
120
  self.download_data_button_id,
118
121
  )
119
122
 
123
+ def get_stacked_bar_chart_for_download(self):
124
+ """Return fig with title and subtitle for download as png"""
125
+ return get_chart_for_download(self, self.create_stacked_bar_chart())
126
+
120
127
  def create_stacked_bar_chart(
121
128
  self,
122
129
  ):
@@ -30,6 +30,9 @@ from gov_uk_dashboards.components.helpers.plotting_helper_functions import (
30
30
  get_legend_configuration,
31
31
  get_rgba_from_hex_colour_and_alpha,
32
32
  )
33
+ from gov_uk_dashboards.components.helpers.get_chart_for_download import (
34
+ get_chart_for_download,
35
+ )
33
36
  from gov_uk_dashboards.components.helpers.update_layout_bgcolor_margin import (
34
37
  update_layout_bgcolor_margin,
35
38
  )
@@ -129,6 +132,10 @@ class TimeSeriesChart:
129
132
  self.download_data_button_id,
130
133
  )
131
134
 
135
+ def get_time_series_chart_for_download(self):
136
+ """Return fig with title and subtitle for download as png"""
137
+ return get_chart_for_download(self, self.create_time_series_chart())
138
+
132
139
  def create_time_series_chart(
133
140
  self,
134
141
  ):
@@ -156,6 +163,7 @@ class TimeSeriesChart:
156
163
  line={"color": line_color},
157
164
  hoverinfo="skip", # 👈 This line disables hover for this trace
158
165
  showlegend=False, # Optional: hide it from legend too
166
+ legendgroup=self.additional_line["legend_group"],
159
167
  )
160
168
  fig.add_trace(trace_connector)
161
169
  # pylint: disable=unused-variable
@@ -173,12 +181,14 @@ class TimeSeriesChart:
173
181
  marker_sizes = [0] + [12] * (len(df.with_row_count()) - 1)
174
182
  else:
175
183
  marker_sizes = [12] * (len(df.with_row_count()))
184
+ legendgroup = self._get_legend_group(df)
176
185
  fig.add_trace(
177
186
  self.create_time_series_trace(
178
187
  df.sort(self.x_axis_column),
179
188
  trace_name,
180
189
  line_style={"dash": "solid", "color": colour},
181
190
  marker={"symbol": marker, "size": marker_sizes, "opacity": 1},
191
+ legendgroup=legendgroup,
182
192
  ),
183
193
  )
184
194
 
@@ -220,6 +230,7 @@ class TimeSeriesChart:
220
230
  ]
221
231
 
222
232
  hover_text_full = hover_text + hover_text[::-1]
233
+ legendgroup = self._get_legend_group(fill_df)
223
234
  fig.add_trace(
224
235
  go.Scatter(
225
236
  x=x_series + x_series[::-1],
@@ -232,6 +243,7 @@ class TimeSeriesChart:
232
243
  name=self.filled_traces_dict["name"] + LEGEND_SPACING,
233
244
  hovertemplate=hover_text_full,
234
245
  hoveron="points",
246
+ legendgroup=legendgroup,
235
247
  )
236
248
  )
237
249
  self._format_x_axis(fig)
@@ -299,6 +311,14 @@ class TimeSeriesChart:
299
311
  )
300
312
  return fig
301
313
 
314
+ def _get_legend_group(self, df):
315
+ if "legend_group" in df.columns and len(df) > 0:
316
+ value = df["legend_group"][0]
317
+ legendgroup = value if value is not None else None
318
+ else:
319
+ legendgroup = None
320
+ return legendgroup
321
+
302
322
  # pylint: disable=duplicate-code
303
323
  def _format_x_axis(self, fig):
304
324
  tick_text, tick_values, range_x = self._get_x_axis_content()
@@ -317,6 +337,7 @@ class TimeSeriesChart:
317
337
  trace_name: str,
318
338
  line_style: dict[str, str],
319
339
  marker: dict[str, str],
340
+ legendgroup: str,
320
341
  ):
321
342
  """Creates a trace for the plot.
322
343
 
@@ -326,6 +347,7 @@ class TimeSeriesChart:
326
347
  trace_name (str): Name of trace.
327
348
  line_style (dict[str, str]): Properties for line_style parameter.
328
349
  marker (dict[str,str]): Properties for marker parameter.
350
+ legendgroup (str): Name to group by in legend,
329
351
  """
330
352
  return go.Scatter(
331
353
  x=df[self.x_axis_column],
@@ -339,6 +361,7 @@ class TimeSeriesChart:
339
361
  showlegend=(
340
362
  trace_name in self.legend_dict if self.legend_dict is not None else True
341
363
  ),
364
+ legendgroup=legendgroup,
342
365
  )
343
366
 
344
367
  def _get_hover_template(self, df, trace_name):
@@ -18,3 +18,9 @@ UNIT_SIZE = "Unit size"
18
18
  DEFAULT_COLOURSCALE = "tealgrn"
19
19
 
20
20
  LEGEND_SPACING = "\u00A0" * 5
21
+
22
+ DOWNLOAD_BUTTON_CLASSES = (
23
+ "govuk-button govuk-button--primary "
24
+ "govuk-!-margin-bottom-0 govuk-!-margin-top-4 "
25
+ "flex w-auto items-center gap-2 print:hidden"
26
+ )
@@ -0,0 +1,16 @@
1
+ """convert_fig_to_image_and_download"""
2
+
3
+ import plotly.graph_objects as go
4
+ import plotly.io as pio
5
+ from dash import dcc
6
+
7
+
8
+ def convert_fig_to_image_and_download(fig: go.Figure, name: str):
9
+ """Converts a given Plotly figure to a PNG image and returns a Dash component
10
+ for downloading the image.
11
+ """
12
+ fig.update_layout(margin={"t": 150, "b": 100, "l": 100, "r": 50})
13
+
14
+ filename = f"{name}-chart.png"
15
+ img_bytes = pio.to_image(fig, format="png", width=1600, height=800)
16
+ return dcc.send_bytes(img_bytes, filename)
@@ -0,0 +1,114 @@
1
+ """download_csv_with_headers"""
2
+ import io
3
+ import polars as pl
4
+ from dash import dcc
5
+ from gov_uk_dashboards.lib.datetime_functions.datetime_functions import (
6
+ get_todays_date_for_downloaded_csv,
7
+ )
8
+
9
+
10
+ def download_csv_with_headers(
11
+ list_of_df_title_subtitle_dicts: list[dict[str, str]],
12
+ name: str,
13
+ sensitivity_label: str,
14
+ additional_text: list[str] = None,
15
+ ): # pylint: disable=too-many-locals
16
+ """Adds a header above multiple dataframes,
17
+ separates them with blank rows, and downloads as CSV.
18
+
19
+ Args:
20
+ list_of_df_title_subtitle_dicts (list[dict[]]): List of dictionaries containing keys: "df",
21
+ "title" and "subtitle"
22
+ name (str): Filename for CSV.
23
+ sensitivity_label (str): Sensitivity label. Str or None.
24
+ additional_text (list[str]): Additional text to inlcude in headers after data downloaded.
25
+ Str or None.
26
+ """
27
+
28
+ csv_buffer = io.StringIO()
29
+
30
+ column_list = list(list_of_df_title_subtitle_dicts[0]["df"].columns)
31
+ column_dict = {column_name: column_name for column_name in column_list}
32
+ blank_dict = {
33
+ f"{i}": None
34
+ for i in range(
35
+ _get_number_of_max_columns_from_all_dfs(list_of_df_title_subtitle_dicts)
36
+ - len(column_list)
37
+ )
38
+ } # range is missing columns in first df compared to max columns across all dfs
39
+
40
+ subtitle = list_of_df_title_subtitle_dicts[0]["subtitle"]
41
+
42
+ header_data = [
43
+ {column_list[0]: "Date downloaded: " + get_todays_date_for_downloaded_csv()},
44
+ *(
45
+ [{column_list[0]: text} for text in additional_text]
46
+ + [{column_list[0]: None}]
47
+ if additional_text is not None
48
+ else []
49
+ ),
50
+ {column_list[0]: list_of_df_title_subtitle_dicts[0]["title"]},
51
+ *(
52
+ [{column_list[0]: subtitle}] if subtitle is not None else []
53
+ ), # Uses unpacking (*) to add the subtitle row if subtitle is not None. If subtitle is
54
+ # None, it unpacks an empty list, effectively skipping the row.
55
+ {column_list[0]: None}, # Blank row
56
+ {**column_dict, **blank_dict},
57
+ ]
58
+
59
+ if sensitivity_label:
60
+ header_data = [{column_list[0]: sensitivity_label}] + header_data
61
+
62
+ pl.DataFrame(header_data).write_csv(csv_buffer, include_header=False)
63
+
64
+ for i, data in enumerate(list_of_df_title_subtitle_dicts):
65
+ df = data["df"]
66
+ title = data["title"]
67
+ subtitle = data["subtitle"]
68
+
69
+ if i > 0 and title is not None:
70
+ column_dict = {column_name: column_name for column_name in list(df.columns)}
71
+ header_data = [
72
+ {column_list[0]: title},
73
+ *(
74
+ [{column_list[0]: subtitle}] if subtitle is not None else []
75
+ ), # Uses unpacking (*) to add the subtitle row if subtitle is not None. If
76
+ # subtitle is None, it unpacks an empty list, effectively skipping the row.
77
+ {column_list[0]: None}, # Blank row
78
+ ]
79
+ pl.DataFrame(header_data).write_csv(csv_buffer, include_header=False)
80
+ df.write_csv(csv_buffer, include_header=i > 0)
81
+
82
+ if i < len(list_of_df_title_subtitle_dicts) - 1:
83
+ blank_row = pl.DataFrame({df.columns[0]: [None]})
84
+ blank_row.write_csv(csv_buffer, include_header=False)
85
+
86
+ csv_buffer.seek(0)
87
+ csv_data = (
88
+ "\ufeff" + csv_buffer.getvalue()
89
+ ) # Adding \ufeff ensures the correct character encoding is detected for £
90
+
91
+ return dcc.send_string(csv_data, f"{name}.csv")
92
+
93
+
94
+ def _get_number_of_max_columns_from_all_dfs(list_of_df_title_subtitle_dicts):
95
+ max_columns = 0
96
+ index_of_max_cols = -1
97
+
98
+ for idx, dic in enumerate(list_of_df_title_subtitle_dicts):
99
+ # Get the DataFrame
100
+ df = dic["df"]
101
+
102
+ # Get the number of columns
103
+ num_columns = df.shape[1]
104
+
105
+ # Update if this DataFrame has more columns
106
+ if num_columns > max_columns:
107
+ max_columns = num_columns
108
+ index_of_max_cols = idx
109
+
110
+ max_columns = len(
111
+ list(list_of_df_title_subtitle_dicts[index_of_max_cols]["df"].columns)
112
+ )
113
+
114
+ return max_columns
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gov_uk_dashboards
3
- Version: 16.1.0
3
+ Version: 17.0.0
4
4
  Summary: Provides access to functionality common to creating a data dashboard.
5
5
  Author: Department for Levelling Up, Housing and Communities
6
6
  Description-Content-Type: text/markdown
@@ -51,8 +51,6 @@ gov_uk_dashboards/components/dash/card_full_width.py
51
51
  gov_uk_dashboards/components/dash/collapsible_panel.py
52
52
  gov_uk_dashboards/components/dash/comparison_la_filter_button.py
53
53
  gov_uk_dashboards/components/dash/context_banner.py
54
- gov_uk_dashboards/components/dash/create_download_chart_button.py
55
- gov_uk_dashboards/components/dash/create_download_data_button.py
56
54
  gov_uk_dashboards/components/dash/dashboard_container.py
57
55
  gov_uk_dashboards/components/dash/details.py
58
56
  gov_uk_dashboards/components/dash/download_button.py
@@ -81,6 +79,7 @@ gov_uk_dashboards/components/dash/warning_text.py
81
79
  gov_uk_dashboards/components/helpers/__init__.py
82
80
  gov_uk_dashboards/components/helpers/display_chart_or_table_with_header.py
83
81
  gov_uk_dashboards/components/helpers/generate_dash_graph_from_figure.py
82
+ gov_uk_dashboards/components/helpers/get_chart_for_download.py
84
83
  gov_uk_dashboards/components/helpers/plotting_helper_functions.py
85
84
  gov_uk_dashboards/components/helpers/update_layout_bgcolor_margin.py
86
85
  gov_uk_dashboards/components/plotly/__init__.py
@@ -108,4 +107,7 @@ gov_uk_dashboards/lib/dap/__init__.py
108
107
  gov_uk_dashboards/lib/dap/dap_deployment.py
109
108
  gov_uk_dashboards/lib/dap/get_dataframe_from_cds.py
110
109
  gov_uk_dashboards/lib/datetime_functions/__init__.py
111
- gov_uk_dashboards/lib/datetime_functions/datetime_functions.py
110
+ gov_uk_dashboards/lib/datetime_functions/datetime_functions.py
111
+ gov_uk_dashboards/lib/download_functions/__init__.py
112
+ gov_uk_dashboards/lib/download_functions/convert_fig_to_image_and_download.py
113
+ gov_uk_dashboards/lib/download_functions/download_csv_with_headers.py
@@ -10,7 +10,7 @@ setup(
10
10
  author="Department for Levelling Up, Housing and Communities",
11
11
  description="Provides access to functionality common to creating a data dashboard.",
12
12
  name="gov_uk_dashboards",
13
- version="16.1.0",
13
+ version="17.0.0",
14
14
  long_description=long_description,
15
15
  long_description_content_type="text/markdown",
16
16
  packages=find_packages(),
@@ -1,25 +0,0 @@
1
- """create_download_chart_button"""
2
-
3
- from dash import html
4
- from gov_uk_dashboards.components.dash import download_button_with_icon
5
-
6
-
7
- def create_download_chart_button(button_id_name: str) -> html.Div:
8
- """Create a download button for charts, aligned to the right.
9
-
10
- Parameters:
11
- - button_id_name (str): A unique identifier for the button.
12
-
13
- Returns:
14
- - html.Div: A Div element containing a download button.
15
- """
16
- return html.Div(
17
- download_button_with_icon(
18
- button_text="Download chart",
19
- button_id={
20
- "download-type": "download-chart",
21
- "name": button_id_name,
22
- },
23
- ),
24
- style={"textAlign": "right"},
25
- )
@@ -1,25 +0,0 @@
1
- """create_download_data_button"""
2
-
3
- from dash import html
4
- from gov_uk_dashboards.components.dash import download_button_with_icon
5
-
6
-
7
- def create_download_data_button(button_id_name: str) -> html.Div:
8
- """Create a download button for data, aligned to the right.
9
-
10
- Parameters:
11
- - button_id_name (str): A unique identifier for the button.
12
-
13
- Returns:
14
- - html.Div: A Div element containing a download button.
15
- """
16
- return html.Div(
17
- download_button_with_icon(
18
- button_text=".csv",
19
- button_id={
20
- "download-type": "download-data",
21
- "name": button_id_name,
22
- },
23
- ),
24
- style={"float": "left", "margin-top": "-20px"},
25
- )
@@ -1,62 +0,0 @@
1
- """download_button"""
2
- import warnings
3
- from dash import html
4
-
5
-
6
- def download_button(button_text: str, button_id: str = "download-button"):
7
- """
8
- Return a download button which is aligned to the right
9
-
10
- Args:
11
- button_text (str): The text to display on the button.
12
- button_id: (str, Optional) = id for dropdown, default to "download-button"
13
- """
14
- warnings.warn(
15
- "Note there is an alternative function to download_button() called "
16
- "download_button_with_icon() which includes a download icon and improved styling.",
17
- Warning,
18
- stacklevel=2,
19
- )
20
-
21
- return html.Div(
22
- [
23
- html.Button(
24
- button_text,
25
- id=button_id,
26
- n_clicks=0,
27
- className="govuk-button govuk-button--secondary",
28
- ),
29
- ],
30
- className="govuk-button-group",
31
- style={"float": "right"},
32
- )
33
-
34
-
35
- def download_button_with_icon(button_text: str, button_id: str = "download-button"):
36
- """
37
- Return a download button styled with additional classes and an SVG icon,
38
- aligned to the right.
39
-
40
- Args:
41
- button_text (str): The text to display on the button.
42
- button_id (str, Optional): ID for the button, defaults to "download-button".
43
- """
44
- classes = (
45
- "govuk-button govuk-button--primary "
46
- "govuk-!-margin-bottom-0 govuk-!-margin-top-4 "
47
- "flex w-auto items-center gap-2 print:hidden"
48
- )
49
- return html.Div(
50
- [
51
- html.Button(
52
- [html.Div("", className="download-icon"), button_text],
53
- id=button_id,
54
- n_clicks=0,
55
- className=classes,
56
- type="submit",
57
- style={"display": "flex", "alignItems": "center", "gap": "8px"},
58
- ),
59
- ],
60
- className="govuk-button-group",
61
- style={"float": "right"},
62
- )