Repository: python-visualization/folium

Issue:
Choropleth key_on doesn't allow for traversing an array
**Is your feature request related to a problem? Please describe.**
Can't match based on a property which hides the property you need in an array. Such as the following in a geojson for Canadian provinces I want to use:

```json
"properties":{
   "geo_point_2d":{
      "lon":-114.51101438986483,
      "lat":55.16890299842028
   },
   "year":"2021",
   "prov_code":[
      "48"
   ],
   "prov_name_en":[
      "Alberta"
   ],
   "prov_area_code":"CAN",
   "prov_type":"province",
   "prov_name_fr":"Alberta"
}
```

I'm not sure why this hides the English province name in an array, but if I've run into this I'm sure it could be an issue for someone else at some point too.

**Describe the solution you'd like**

Either `feature.properties.prov_name_en.0` or `feature.properties.prov_name_en[0]` should work.

**Describe alternatives you've considered**

Alternatives above, short of implementation I must modify the file for now.

**Additional context**

**Implementation**
folium is maintained by volunteers. Can you help make a PR if we want to implement this feature?

I would consider helping with PR if given guidance on preferred implementation.


Discussion:
Conengmo: Thanks Amrutha! I'll take a closer look shortly. Just wanted to say already it would be good to add a test for `get_by_key`. That would require moving it up a level so it becomes a 'proper' method on the class. Since it's not for consumption also make it private by prepending an underscore: `_get_by_key`.
amrutharajashekar: Thanks for the pointers Conengmo , will work on them over the weekend and get back to you!
amrutharajashekar: Hi @Conengmo How do we test for pre-commit check locally ?
martinfleis: @amrutharajashekar 

You must first install pre-commit:

```sh
pip install pre-commit
```

From the root of the folium repository, you should then install the pre-commit included in Folium:
```sh
pre-commit install
```
Then checks will be run automatically each time you commit changes. You can skip these checks with `git commit --no-verify`.

Patch:
diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml
index aa09fd44..a51fae16 100644
--- a/.github/workflows/pypi.yml
+++ b/.github/workflows/pypi.yml
@@ -46,7 +46,7 @@ jobs:
 
     - name: Publish a Python distribution to PyPI
       if: success() && github.event_name == 'release'
-      uses: pypa/gh-action-pypi-publish@v1.8.6
+      uses: pypa/gh-action-pypi-publish@v1.8.7
       with:
         user: __token__
         password: ${{ secrets.PYPI_PASSWORD }}
diff --git a/folium/features.py b/folium/features.py
index 5792290d..05718ce9 100644
--- a/folium/features.py
+++ b/folium/features.py
@@ -1552,17 +1552,8 @@ class Choropleth(FeatureGroup):
 
             key_on = key_on[8:] if key_on.startswith("feature.") else key_on
 
-            def get_by_key(obj, key):
-                return (
-                    obj.get(key, None)
-                    if len(key.split(".")) <= 1
-                    else get_by_key(
-                        obj.get(key.split(".")[0], None), ".".join(key.split(".")[1:])
-                    )
-                )
-
             def color_scale_fun(x):
-                key_of_x = get_by_key(x, key_on)
+                key_of_x = self._get_by_key(x, key_on)
                 if key_of_x is None:
                     raise ValueError(f"key_on `{key_on!r}` not found in GeoJSON.")
 
@@ -1623,6 +1614,20 @@ class Choropleth(FeatureGroup):
         if self.color_scale:
             self.add_child(self.color_scale)
 
+    @classmethod
+    def _get_by_key(cls, obj: Union[dict, list], key: str) -> Union[float, str, None]:
+        key_parts = key.split(".")
+        first_key_part = key_parts[0]
+        if first_key_part.isdigit():
+            value = obj[int(first_key_part)]
+        else:
+            value = obj.get(first_key_part, None)  # type: ignore
+        if len(key_parts) > 1:
+            new_key = ".".join(key_parts[1:])
+            return cls._get_by_key(value, new_key)
+        else:
+            return value
+
     def render(self, **kwargs) -> None:
         """Render the GeoJson/TopoJson and color scale objects."""
         if self.color_scale:
diff --git a/folium/plugins/draw.py b/folium/plugins/draw.py
index 75ceaef9..95155f8e 100644
--- a/folium/plugins/draw.py
+++ b/folium/plugins/draw.py
@@ -51,10 +51,10 @@ class Draw(JSCSSMixin, MacroElement):
               edit: {{ this.edit_options|tojson }},
             }
             // FeatureGroup is to store editable layers.
-            var drawnItems = new L.featureGroup().addTo(
+            var drawnItems_{{ this.get_name() }} = new L.featureGroup().addTo(
                 {{ this._parent.get_name() }}
             );
-            options.edit.featureGroup = drawnItems;
+            options.edit.featureGroup = drawnItems_{{ this.get_name() }};
             var {{ this.get_name() }} = new L.Control.Draw(
                 options
             ).addTo( {{this._parent.get_name()}} );
@@ -68,14 +68,14 @@ class Draw(JSCSSMixin, MacroElement):
                     console.log(coords);
                 });
                 {%- endif %}
-                drawnItems.addLayer(layer);
+                drawnItems_{{ this.get_name() }}.addLayer(layer);
              });
             {{ this._parent.get_name() }}.on('draw:created', function(e) {
-                drawnItems.addLayer(e.layer);
+                drawnItems_{{ this.get_name() }}.addLayer(e.layer);
             });
             {% if this.export %}
             document.getElementById('export').onclick = function(e) {
-                var data = drawnItems.toGeoJSON();
+                var data = drawnItems_{{ this.get_name() }}.toGeoJSON();
                 var convertedData = 'text/json;charset=utf-8,'
                     + encodeURIComponent(JSON.stringify(data));
                 document.getElementById('export').setAttribute(


Test patch:
diff --git a/tests/test_features.py b/tests/test_features.py
index 6a4185b8..c879ad11 100644
--- a/tests/test_features.py
+++ b/tests/test_features.py
@@ -12,7 +12,7 @@ import pytest
 from branca.element import Element
 
 import folium
-from folium import ClickForMarker, GeoJson, Map, Popup
+from folium import Choropleth, ClickForMarker, GeoJson, Map, Popup
 
 
 @pytest.fixture
@@ -302,3 +302,27 @@ def test_geometry_collection_get_bounds():
         "type": "GeometryCollection",
     }
     assert folium.GeoJson(geojson_data).get_bounds() == [[0, -3], [4, 2]]
+
+
+def test_choropleth_get_by_key():
+    geojson_data = {
+        "id": "0",
+        "type": "Feature",
+        "properties": {"idx": 0, "value": 78.0},
+        "geometry": {
+            "type": "Polygon",
+            "coordinates": [
+                [
+                    [1, 2],
+                    [3, 4],
+                ]
+            ],
+        },
+    }
+
+    # Test with string path in key_on
+    assert Choropleth._get_by_key(geojson_data, "properties.idx") == 0
+    assert Choropleth._get_by_key(geojson_data, "properties.value") == 78.0
+
+    # Test with combined string path and numerical index in key_on
+    assert Choropleth._get_by_key(geojson_data, "geometry.coordinates.0.0") == [1, 2]