gov-uk-dashboards 17.0.0__py3-none-any.whl → 17.1.0__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.
@@ -0,0 +1,44 @@
1
+ window.myNamespace = Object.assign({}, window.myNamespace, {
2
+ mapColorScaleFunctions: {
3
+ continuousColorScale: function(feature, context) {
4
+ const {
5
+ colorscale,
6
+ colorProp,
7
+ style,
8
+ min,
9
+ max
10
+ } = context.hideout;
11
+ const value = feature.properties[colorProp];
12
+ const colors = Array.from(colorscale); // defensive copy
13
+ if (value === null || value === undefined) {
14
+ return {
15
+ ...style,
16
+ fillColor: "#b1b4b6"
17
+ };
18
+ }
19
+ // Normalize value to 0-1
20
+ const t = (value - min) / (max - min);
21
+
22
+ // Helper: interpolate between two hex colors
23
+ function interpolateColor(color1, color2, t) {
24
+ const c1 = parseInt(color1.slice(1), 16);
25
+ const c2 = parseInt(color2.slice(1), 16);
26
+ const r = Math.round(((c2 >> 16) - (c1 >> 16)) * t + (c1 >> 16));
27
+ const g = Math.round((((c2 >> 8) & 0xFF) - ((c1 >> 8) & 0xFF)) * t + ((c1 >> 8) & 0xFF));
28
+ const b = Math.round(((c2 & 0xFF) - (c1 & 0xFF)) * t + (c1 & 0xFF));
29
+ return `rgb(${r},${g},${b})`;
30
+ }
31
+
32
+ // Find segment and interpolate
33
+ const n = colors.length - 1;
34
+ const idx = Math.min(Math.floor(t * n), n - 1);
35
+ const local_t = (t * n) - idx;
36
+ const fillColor = interpolateColor(colors[idx], colors[idx + 1], local_t);
37
+
38
+ return {
39
+ ...style,
40
+ fillColor: fillColor
41
+ };
42
+ }
43
+ }
44
+ });
File without changes
@@ -0,0 +1,174 @@
1
+ """Leaflet choropleth map class"""
2
+
3
+ from dash_extensions.javascript import arrow_function, Namespace
4
+ import dash_leaflet as dl
5
+ from dash import html
6
+ import polars as pl
7
+
8
+ from gov_uk_dashboards.formatting.number_formatting import (
9
+ format_number_into_thousands_or_millions,
10
+ )
11
+
12
+
13
+ class LeafletChoroplethMap:
14
+ """Class for generating leaflet choropleth map charts.
15
+ Note: dataframe_function must contain columns: 'Region', 'Area_Code',
16
+ column_to_plot, hover_text_columns
17
+ If color_scale_is_discrete is false, colour scale will be continuous, otherwise it will be
18
+ discrete"""
19
+
20
+ # pylint: disable=too-few-public-methods
21
+
22
+ def __init__(
23
+ self,
24
+ get_geojson_function,
25
+ get_df_function,
26
+ hover_text_columns,
27
+ color_scale_is_discrete=True,
28
+ ):
29
+ self.geojson_data = get_geojson_function()
30
+ self.df = get_df_function()
31
+ self.hover_text_columns = hover_text_columns
32
+ self.color_scale_is_discrete = color_scale_is_discrete
33
+ self._add_data_to_geojson()
34
+
35
+ def get_leaflet_choropleth_map(self):
36
+ """Creates and returns leaflet choropleth map chart for display on application.
37
+
38
+ Returns:
39
+ dl.Map: A dash leaflet map chart.
40
+ """
41
+ return dl.Map(
42
+ children=[
43
+ dl.TileLayer(),
44
+ self._get_colorbar(),
45
+ self._get_colorbar_title(),
46
+ self._get_dl_geojson(),
47
+ ],
48
+ center=[54.5, -2.5], # Centered on the UK
49
+ zoom=6.5,
50
+ minZoom=6.5,
51
+ maxZoom=6.5,
52
+ maxBounds=[[49.8, -10], [55.9, 1.8]],
53
+ scrollWheelZoom=False, # Disable zooming via mouse scroll
54
+ dragging=False, # Optional: prevent dragging too if you want
55
+ zoomControl=False, # Hide the zoom buttons (+/-)
56
+ doubleClickZoom=False, # Prevent double click zoom
57
+ touchZoom=False, # Prevent pinch zoom
58
+ attributionControl=False,
59
+ style={"width": "100%", "height": "800px", "background": "white"},
60
+ )
61
+
62
+ def _add_data_to_geojson(self):
63
+ info_map = {
64
+ row["Area_Code"]: {
65
+ "value": row["Value"],
66
+ "region": row["Region"],
67
+ **{col: row[col] for col in self.hover_text_columns},
68
+ }
69
+ for row in self.df.iter_rows(named=True)
70
+ }
71
+
72
+ for feature in self.geojson_data["features"]:
73
+ region_code = feature["properties"]["geo_id"]
74
+ info = info_map.get(region_code)
75
+ if info:
76
+
77
+ feature["properties"]["density"] = info["value"]
78
+ feature["properties"]["region"] = info["region"]
79
+
80
+ tooltip_parts = [f"<b>{info['region']}</b>"]
81
+ if info["value"] is None:
82
+ tooltip_parts.append("<br>No data available")
83
+ else:
84
+ for col in self.hover_text_columns:
85
+ tooltip_parts.append(f"<br>{col}: {info[col]}")
86
+
87
+ feature["properties"]["tooltip"] = "".join(tooltip_parts)
88
+ else:
89
+ feature["properties"]["density"] = None
90
+ feature["properties"]["region"] = "Unknown"
91
+ feature["properties"]["tooltip"] = "No data available"
92
+
93
+ def _get_dl_geojson(self):
94
+ style_handle = self._get_style_handle()
95
+ colorscale = self._get_colorscale()
96
+ style = {"weight": 2, "opacity": 1, "color": "white", "fillOpacity": 1}
97
+ hover_style = arrow_function({"weight": 5, "color": "#666", "dashArray": ""})
98
+ return dl.GeoJSON(
99
+ data=self.geojson_data,
100
+ id="geojson",
101
+ zoomToBounds=True,
102
+ zoomToBoundsOnClick=True,
103
+ style=style_handle,
104
+ hoverStyle=hover_style,
105
+ hideout={
106
+ "colorscale": colorscale, # Use hex strings
107
+ "style": style,
108
+ "colorProp": "density",
109
+ "min": self.df["Value"].min(),
110
+ "max": self.df["Value"].max(),
111
+ },
112
+ )
113
+
114
+ def _get_style_handle(self):
115
+ ns = Namespace("myNamespace", "mapColorScaleFunctions")
116
+ if self.color_scale_is_discrete:
117
+ return ""
118
+ return ns("continuousColorScale")
119
+
120
+ def _get_colorscale(self):
121
+ if self.color_scale_is_discrete:
122
+ return ""
123
+ return ["#B0F2BC", "#257D98"]
124
+
125
+ def _get_colorbar(self):
126
+ min_value = self.df.select(pl.min("Value")).item()
127
+ colorbar_min = min(min_value, 0)
128
+ max_value = self.df.select(pl.max("Value")).item()
129
+ mid_value = (colorbar_min + max_value) / 2
130
+ quarter_value = (colorbar_min + max_value) / 4
131
+ three_quarter_value = 3 * (colorbar_min + max_value) / 4
132
+ tick_values = [
133
+ colorbar_min,
134
+ quarter_value,
135
+ mid_value,
136
+ three_quarter_value,
137
+ max_value,
138
+ ]
139
+ tick_text = [
140
+ format_number_into_thousands_or_millions(x) for x in tick_values
141
+ ] # Optional, for formatting
142
+
143
+ return dl.Colorbar(
144
+ colorscale=self._get_colorscale(),
145
+ width=20,
146
+ height=200,
147
+ min=colorbar_min,
148
+ max=max_value,
149
+ position="topleft",
150
+ style={
151
+ "backgroundColor": "white",
152
+ "padding": "5px",
153
+ "borderRadius": "4px",
154
+ "marginTop": "100px",
155
+ },
156
+ tickValues=tick_values,
157
+ tickText=tick_text, # Optional, makes labels look cleaner
158
+ )
159
+
160
+ def _get_colorbar_title(self):
161
+ return html.Div(
162
+ self.hover_text_columns[0],
163
+ style={
164
+ "position": "absolute",
165
+ "bottom": "700px", # Adjusted to place above the colorbar
166
+ "left": "10px", # Align with the left side of the colorbar
167
+ "background": "white",
168
+ "padding": "2px 6px",
169
+ "borderRadius": "5px",
170
+ "fontWeight": "bold",
171
+ "fontSize": "14px",
172
+ "zIndex": "999", # Ensure it appears above map elements
173
+ },
174
+ )
@@ -0,0 +1,24 @@
1
+ """Functions to add formatting to number values"""
2
+
3
+
4
+ def format_number_into_thousands_or_millions(
5
+ number: int, thousand_decimal_places: int = 0
6
+ ) -> str:
7
+ """Format number into thousands or millions, eg. 1,500 becomes 1.5k & 1,234,567 becomes 1.235m
8
+
9
+ Args:
10
+ number (int): Integer to format.
11
+ thousand_decimal_places (int or str): The number of decimal places to display for
12
+ 1_000<=number<1_000_000. Defaults to 0. If "default" is passed, number is simply
13
+ divided by 1_000.
14
+ """
15
+ if number >= 1_000_000:
16
+ formatted_number = f"{number / 1_000_000:.3f}m"
17
+ elif number >= 1_000:
18
+ if thousand_decimal_places == "default":
19
+ formatted_number = f"{number / 1_000}k"
20
+ else:
21
+ formatted_number = f"{number / 1_000:.{thousand_decimal_places}f}k"
22
+ else:
23
+ formatted_number = str(number)
24
+ return formatted_number
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gov_uk_dashboards
3
- Version: 17.0.0
3
+ Version: 17.1.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
@@ -7,6 +7,7 @@ gov_uk_dashboards/template.html,sha256=uFAki9bEpcei5dP_NZYP8dsxpxXpNIDQPn7ezsE7V
7
7
  gov_uk_dashboards/template.py,sha256=WNVkAW3LCNoUHcxQ1kiUPkGCKIan5DgZQaAA_ZbE5WA,534
8
8
  gov_uk_dashboards/assets/__init__.py,sha256=SwV4sjjMQmuZXloVcvf2H86XFiAd8xhPLJvaSMC2MQE,101
9
9
  gov_uk_dashboards/assets/attach-event-to-dash.js,sha256=mbea5TaxEnjMN-MebR3J0hVjOb1B27-zXwWw9ZYqBBw,562
10
+ gov_uk_dashboards/assets/custom_map_style_functions.js,sha256=1-jnhguDEn7-BnleGbSTB-dlaSO-6hPF-JL0d5EUnhU,1689
10
11
  gov_uk_dashboards/assets/dashboard.css,sha256=exnujRlse2xHOeuE_TAs84gITv5YMRzKJKEeSjoXO6U,202134
11
12
  gov_uk_dashboards/assets/get_assets_folder.py,sha256=ozYOmuO2r36vaTdWMU5cBuskl47RHBp8z9KIO06BXBM,171
12
13
  gov_uk_dashboards/assets/govuk-frontend-3.14.0.min.js,sha256=kKi_r2hAqumi2pKM43W8NKpR2UtksUww9lSQOjkOmMI,34806
@@ -73,6 +74,8 @@ gov_uk_dashboards/components/helpers/generate_dash_graph_from_figure.py,sha256=s
73
74
  gov_uk_dashboards/components/helpers/get_chart_for_download.py,sha256=RS5SR2tCQPTkBpWaIr2mb98Yn6vAimBnAXpRhMx0kB4,669
74
75
  gov_uk_dashboards/components/helpers/plotting_helper_functions.py,sha256=moD2tse2FqTBW2rOHOvZCL9BIlmDbyvU5233yFFu_aI,1635
75
76
  gov_uk_dashboards/components/helpers/update_layout_bgcolor_margin.py,sha256=i7Nwp0CxFpkyQeR8KfOBVMBkzctG7hMpWI2OzgxB2jY,740
77
+ gov_uk_dashboards/components/leaflet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
+ gov_uk_dashboards/components/leaflet/leaflet_choropleth_map.py,sha256=4ysc-FxRKGPSkNuJBDtjlEOGthC7EuIliaillqX2GeI,6221
76
79
  gov_uk_dashboards/components/plotly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
80
  gov_uk_dashboards/components/plotly/captioned_figure.py,sha256=T0sbtGTiJ79FXxVdPb__hqISuyTc3Dl11cKhgcuW-5U,2804
78
81
  gov_uk_dashboards/components/plotly/choropleth_map.py,sha256=U9RmS3MZGloQAt9HoSYh3Xad205DDfZOjz91ZD_ydbI,9849
@@ -88,6 +91,7 @@ gov_uk_dashboards/figures/styles/__init__.py,sha256=wVa8BU0TvXnanksOUVWN4utFKW4O
88
91
  gov_uk_dashboards/figures/styles/line_style.py,sha256=sXc9pGrAVxFrxqXSTsrw0hEgyhmhMOLhqhwx93J-PtI,559
89
92
  gov_uk_dashboards/formatting/__init__.py,sha256=bQk9_OEubUhuTRQjXUs4ZItgSY7yyDpwQcLauxf11Tk,460
90
93
  gov_uk_dashboards/formatting/human_readable.py,sha256=e-ROPS7oFLHCV58MXBIhLsZQut-F-bAYz0TOz33gX2M,1844
94
+ gov_uk_dashboards/formatting/number_formatting.py,sha256=9LVqKqx0mMQyv8XLI_im1pdASZDJxRjzRWtRN-g6kPs,913
91
95
  gov_uk_dashboards/formatting/round_and_add_prefix_and_suffix.py,sha256=_DboRfdvwb9Y62H9LFDFJ0ju4626z-_oFuwagRgyZDY,1456
92
96
  gov_uk_dashboards/formatting/rounding.py,sha256=Em1yri_j18IYHbZ64d3bhVKX-XEllRSM9FzAUo1o6fU,968
93
97
  gov_uk_dashboards/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -102,8 +106,8 @@ gov_uk_dashboards/lib/datetime_functions/datetime_functions.py,sha256=BQgr8I_vFN
102
106
  gov_uk_dashboards/lib/download_functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
107
  gov_uk_dashboards/lib/download_functions/convert_fig_to_image_and_download.py,sha256=JYDpWObBsiKG5Rtk2ElOTgHwfIR0cRmVocr8RlTfPZQ,534
104
108
  gov_uk_dashboards/lib/download_functions/download_csv_with_headers.py,sha256=h50ejODCjoz9z-yqDt6nsE6jN6XxJN1DWH66CjLJiCk,4155
105
- gov_uk_dashboards-17.0.0.dist-info/licenses/LICENSE,sha256=GDiD7Y2Gx7JucPV1JfVySJeah-qiSyBPdpJ6RHCEHTc,1126
106
- gov_uk_dashboards-17.0.0.dist-info/METADATA,sha256=353hurz1uYu_BGDPevUVpUaCmxmoc1BI_NUXobU0aN8,5917
107
- gov_uk_dashboards-17.0.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
108
- gov_uk_dashboards-17.0.0.dist-info/top_level.txt,sha256=gPaN1P3-H3Rgi2me6tt-fX_cxo19CZfA4PjlZPjGRpo,18
109
- gov_uk_dashboards-17.0.0.dist-info/RECORD,,
109
+ gov_uk_dashboards-17.1.0.dist-info/licenses/LICENSE,sha256=GDiD7Y2Gx7JucPV1JfVySJeah-qiSyBPdpJ6RHCEHTc,1126
110
+ gov_uk_dashboards-17.1.0.dist-info/METADATA,sha256=6wQUDbkJ1690nFpTKm5XfCPwIDhvWGgXONm6bI8xoA8,5917
111
+ gov_uk_dashboards-17.1.0.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
112
+ gov_uk_dashboards-17.1.0.dist-info/top_level.txt,sha256=gPaN1P3-H3Rgi2me6tt-fX_cxo19CZfA4PjlZPjGRpo,18
113
+ gov_uk_dashboards-17.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5