From 6c85ddda7d38a1b9c2083470e7835beeaebc6815 Mon Sep 17 00:00:00 2001 From: Josh Kirk <59419126+this-josh@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:45:24 +0000 Subject: [PATCH] Add ability to set font size in plot (#1879) * Added a function to process font sizes * Add ability to set font size in plot and test it * formatting with black * correct import order * move arg to be the last and added a docstring * Update folium/folium.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> * Change to accept em and px made px the default in line with _parse_size. * correct test units * formatting with black * formatting with black * Update tests/test_utilities.py * Update tests/test_utilities.py --------- Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> --- folium/folium.py | 8 +++++++- folium/utilities.py | 10 ++++++++++ tests/test_folium.py | 2 ++ tests/test_utilities.py | 24 ++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/folium/folium.py b/folium/folium.py index 39f2d47f8..b27d4e13d 100644 --- a/folium/folium.py +++ b/folium/folium.py @@ -17,6 +17,7 @@ TypeBounds, TypeJsonValue, _parse_size, + parse_font_size, parse_options, temp_html_filepath, validate_location, @@ -152,6 +153,9 @@ class Map(JSCSSMixin, MacroElement): rare environments) even if they're supported. zoom_control : bool, default True Display zoom controls on the map. + font_size : int or float or string (default: '1rem') + The font size to use for Leaflet, can either be a number or a + string ending in 'rem', 'em', or 'px'. **kwargs Additional keyword arguments are passed to Leaflets Map class: https://leafletjs.com/reference.html#map @@ -186,7 +190,7 @@ class Map(JSCSSMixin, MacroElement): left: {{this.left[0]}}{{this.left[1]}}; top: {{this.top[0]}}{{this.top[1]}}; } - .leaflet-container { font-size: 1rem; } + .leaflet-container { font-size: {{this.font_size}}; } {% endmacro %} @@ -253,6 +257,7 @@ def __init__( disable_3d: bool = False, png_enabled: bool = False, zoom_control: bool = True, + font_size: str = "1rem", **kwargs: TypeJsonValue, ): super().__init__() @@ -276,6 +281,7 @@ def __init__( self.left = _parse_size(left) self.top = _parse_size(top) self.position = position + self.font_size = parse_font_size(font_size) max_bounds_array = ( [[min_lat, min_lon], [max_lat, max_lon]] if max_bounds else None diff --git a/folium/utilities.py b/folium/utilities.py index 98c757599..fe5bfc2cf 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -428,3 +428,13 @@ def __init__(self, js_code: Union[str, "JsCode"]): self.js_code: str = js_code.js_code else: self.js_code = js_code + + +def parse_font_size(value: Union[str, int, float]) -> str: + """Parse a font size value, if number set as px""" + if isinstance(value, (int, float)): + return f"{value}px" + + if (value[-3:] != "rem") and (value[-2:] not in ["em", "px"]): + raise ValueError("The font size must be expressed in rem, em, or px.") + return value diff --git a/tests/test_folium.py b/tests/test_folium.py index 36533e193..1620bd1b4 100644 --- a/tests/test_folium.py +++ b/tests/test_folium.py @@ -75,6 +75,7 @@ def setup_method(self): max_zoom=20, zoom_start=4, max_bounds=True, + font_size="1.5rem", attr=attr, ) self.env = Environment(loader=PackageLoader("folium", "templates")) @@ -94,6 +95,7 @@ def test_init(self): assert self.m.top == (0, "%") assert self.m.global_switches.no_touch is False assert self.m.global_switches.disable_3d is False + assert self.m.font_size == "1.5rem" assert self.m.to_dict() == { "name": "Map", "id": self.m._id, diff --git a/tests/test_utilities.py b/tests/test_utilities.py index 7d5c44765..2218bba73 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -12,6 +12,7 @@ get_obj_in_upper_tree, if_pandas_df_convert_to_numpy, javascript_identifier_path_to_array_notation, + parse_font_size, parse_options, validate_location, validate_locations, @@ -230,3 +231,26 @@ def test_js_code_init_js_code(): js_code_2 = JsCode(js_code) assert isinstance(js_code_2, JsCode) assert isinstance(js_code_2.js_code, str) + + +@pytest.mark.parametrize( + "value,expected", + [ + (10, "10px"), + (12.5, "12.5px"), + ("1rem", "1rem"), + ("1em", "1em"), + ], +) +def test_parse_font_size_valid(value, expected): + assert parse_font_size(value) == expected + + +invalid_values = ["1", "1unit"] +expected_errors = "The font size must be expressed in rem, em, or px." + + +@pytest.mark.parametrize("value,error_message", zip(invalid_values, expected_errors)) +def test_parse_font_size_invalid(value, error_message): + with pytest.raises(ValueError, match=error_message): + parse_font_size(value)