Repository: geopandas/geopandas

Issue:
ENH: prefer min_zoom and max_zoom arguments instead of tile metadata in explore()
#### Is your feature request related to a problem?

Right now, `xyzservices.TileProvider` metadata overrides `min_zoom` and `max_zoom` arguments and there's essentially no way around it without changing the provider.

#### Describe the solution you'd like

I believe that the preference should be the other way, i.e. if a user specifies `max_zoom`, it should be kept as is and not changed by tiles.

#### API breaking implications

None as far as I can tell

#### Describe alternatives you've considered

You can change tile metadata but that breaks other things in leaflet.

#### Additional context

These two lines need to check if each of the keywords is already present in the `map_kwds` dict and leave it as it is in that case.

https://github.com/geopandas/geopandas/blob/76e886ec23ddd12a032c933ab08b18693a8144a1/geopandas/explore.py#L331-L332



Discussion:
@martinfleis  I would like to work on this.Please assignme this
@soma2000-lang Consider it done, I can't do that technically on GitHub. Thanks!

Resolving patch:
diff --git a/geopandas/explore.py b/geopandas/explore.py
--- a/geopandas/explore.py
+++ b/geopandas/explore.py
@@ -359,8 +359,10 @@ def _colormap_helper(_cmap, n_resample=None, idx=None):
 
             if isinstance(tiles, xyzservices.TileProvider):
                 attr = attr if attr else tiles.html_attribution
-                map_kwds["min_zoom"] = tiles.get("min_zoom", 0)
-                map_kwds["max_zoom"] = tiles.get("max_zoom", 18)
+                if "min_zoom" not in map_kwds:
+                    map_kwds["min_zoom"] = tiles.get("min_zoom", 0)
+                if "max_zoom" not in map_kwds:
+                    map_kwds["max_zoom"] = tiles.get("max_zoom", 18)
                 tiles = tiles.build_url(scale_factor="{r}")
 
         m = folium.Map(


Test patch:
diff --git a/geopandas/tests/test_explore.py b/geopandas/tests/test_explore.py
--- a/geopandas/tests/test_explore.py
+++ b/geopandas/tests/test_explore.py
@@ -693,6 +693,38 @@ def test_xyzservices_query_name(self):
         )
         assert '"maxNativeZoom":20,"maxZoom":20,"minZoom":0' in out_str
 
+    def test_xyzservices_providers_min_zoom_override(self):
+        xyzservices = pytest.importorskip("xyzservices")
+
+        m = self.nybb.explore(
+            tiles=xyzservices.providers.CartoDB.PositronNoLabels, min_zoom=3
+        )
+        out_str = self._fetch_map_string(m)
+
+        assert '"maxNativeZoom":20,"maxZoom":20,"minZoom":3' in out_str
+
+    def test_xyzservices_providers_max_zoom_override(self):
+        xyzservices = pytest.importorskip("xyzservices")
+
+        m = self.nybb.explore(
+            tiles=xyzservices.providers.CartoDB.PositronNoLabels, max_zoom=12
+        )
+        out_str = self._fetch_map_string(m)
+
+        assert '"maxNativeZoom":12,"maxZoom":12,"minZoom":0' in out_str
+
+    def test_xyzservices_providers_both_zooms_override(self):
+        xyzservices = pytest.importorskip("xyzservices")
+
+        m = self.nybb.explore(
+            tiles=xyzservices.providers.CartoDB.PositronNoLabels,
+            min_zoom=3,
+            max_zoom=12,
+        )
+        out_str = self._fetch_map_string(m)
+
+        assert '"maxNativeZoom":12,"maxZoom":12,"minZoom":3' in out_str
+
     def test_linearrings(self):
         rings = self.nybb.explode(index_parts=True).exterior
         m = rings.explore()