Skip to content

keplergl module

KeplerGL implementation of the map widget.

KeplerGLMap (MapWidget)

KeplerGL implementation of the map widget.

Source code in anymap/keplergl.py
class KeplerGLMap(MapWidget):
    """KeplerGL implementation of the map widget."""

    # KeplerGL-specific traits
    map_config = traitlets.Dict({}).tag(sync=True)
    show_docs = traitlets.Bool(False).tag(sync=True)
    read_only = traitlets.Bool(False).tag(sync=True)
    _data = traitlets.Dict({}).tag(sync=True)

    # Define the JavaScript module path
    _esm = _esm_keplergl
    _css = _css_keplergl

    def __init__(
        self,
        center: List[float] = [37.7749, -122.4194],
        zoom: float = 9.0,
        width: str = "100%",
        height: str = "600px",
        show_docs: bool = False,
        read_only: bool = False,
        **kwargs,
    ):
        """Initialize KeplerGL map widget.

        Args:
            center: Map center as [latitude, longitude]
            zoom: Initial zoom level
            width: Widget width
            height: Widget height
            show_docs: Whether to show documentation panel
            read_only: Whether the map is read-only
            **kwargs: Additional widget arguments
        """
        super().__init__(
            center=center,
            zoom=zoom,
            width=width,
            height=height,
            **kwargs,
        )
        self.show_docs = show_docs
        self.read_only = read_only
        self._initialize_config()

    def _initialize_config(self):
        """Initialize the KeplerGL configuration."""
        self.map_config = {
            "version": "v1",
            "config": {
                "mapState": {
                    "latitude": self.center[0],
                    "longitude": self.center[1],
                    "zoom": self.zoom,
                    "bearing": 0,
                    "pitch": 0,
                    "dragRotate": False,
                    "width": self.width,
                    "height": self.height,
                    "isSplit": False,
                },
                "mapStyle": {
                    "styleType": "dark",
                    "topLayerGroups": {},
                    "visibleLayerGroups": {
                        "label": True,
                        "road": True,
                        "border": False,
                        "building": True,
                        "water": True,
                        "land": True,
                        "3d building": False,
                    },
                    "mapStyles": {},
                },
                "visState": {
                    "layers": [],
                    "interactionConfig": {
                        "tooltip": {"fieldsToShow": {}, "enabled": True},
                        "brush": {"size": 0.5, "enabled": False},
                        "geocoder": {"enabled": False},
                        "coordinate": {"enabled": False},
                    },
                    "filters": [],
                    "layerBlending": "normal",
                    "splitMaps": [],
                    "animationConfig": {"currentTime": None, "speed": 1},
                },
            },
        }

    def add_data(self, data: Union[Dict, List], name: str = "dataset") -> None:
        """Add data to the map.

        Args:
            data: Data to add (GeoJSON, DataFrame, etc.)
            name: Name for the dataset
        """
        # Determine data type and format
        if isinstance(data, dict) and data.get("type") == "FeatureCollection":
            # GeoJSON data
            data_type = "geojson"
        elif isinstance(data, list):
            # Array of objects (CSV-like data)
            data_type = "csv"
        else:
            # Default to geojson
            data_type = "geojson"

        # Store the data in the widget's internal data structure
        current_data = dict(self._data)
        current_data[name] = {"type": data_type, "data": data}
        self._data = current_data

    def add_geojson(
        self, geojson: Union[str, Dict], layer_name: str = "geojson_layer", **kwargs
    ) -> None:
        """Add GeoJSON data to the map.

        Args:
            geojson: GeoJSON data (dict or file path)
            layer_name: Name for the layer
            **kwargs: Additional layer configuration
        """
        if isinstance(geojson, str):
            # Load from file
            with open(geojson, "r") as f:
                geojson_data = json.load(f)
        else:
            geojson_data = geojson

        # Store the data in the widget's internal data structure
        current_data = dict(self._data)
        current_data[layer_name] = {"type": "geojson", "data": geojson_data}
        self._data = current_data

    def add_csv(
        self, csv_data: Union[str, List[Dict]], layer_name: str = "csv_layer", **kwargs
    ) -> None:
        """Add CSV data to the map.

        Args:
            csv_data: CSV data (file path or list of dictionaries)
            layer_name: Name for the layer
            **kwargs: Additional layer configuration
        """
        if isinstance(csv_data, str):
            # Load from file
            import pandas as pd

            df = pd.read_csv(csv_data)
            csv_data = df.to_dict("records")
        elif isinstance(csv_data, list):
            # Data is already in the correct format (list of dictionaries)
            pass
        else:
            # Convert other formats to list of dictionaries
            csv_data = [csv_data]

        # Store the data in the widget's internal data structure
        current_data = dict(self._data)
        current_data[layer_name] = {"type": "csv", "data": csv_data}
        self._data = current_data

    def set_filter(self, filter_config: Dict[str, Any]) -> None:
        """Set filter configuration.

        Args:
            filter_config: Filter configuration
        """
        self.call_js_method("setFilter", filter_config)

    def update_map_config(self, config: Dict[str, Any]) -> None:
        """Update the map configuration.

        Args:
            config: New configuration to merge
        """

        # Deep merge the configuration
        def deep_merge(dict1, dict2):
            result = dict1.copy()
            for key, value in dict2.items():
                if (
                    key in result
                    and isinstance(result[key], dict)
                    and isinstance(value, dict)
                ):
                    result[key] = deep_merge(result[key], value)
                else:
                    result[key] = value
            return result

        self.map_config = deep_merge(self.map_config, config)

    def get_map_state(self) -> Dict[str, Any]:
        """Get the current map state.

        Returns:
            Current map state dictionary
        """
        return self.map_config

    def save_config(self, filename: str) -> None:
        """Save the current configuration to a file.

        Args:
            filename: Path to save the configuration
        """
        with open(filename, "w") as f:
            json.dump(self.map_config, f, indent=2)

    def load_config(self, filename: str) -> None:
        """Load configuration from a file.

        Args:
            filename: Path to the configuration file
        """
        with open(filename, "r") as f:
            config = json.load(f)
        self.update_map_config(config)

    def _generate_html_template(
        self, map_state: Dict[str, Any], title: str, **kwargs
    ) -> str:
        """Generate HTML template for KeplerGL."""
        # Serialize map state for JavaScript
        map_state_json = json.dumps(map_state, indent=2)

        # Get the current configuration
        config_json = json.dumps(self.map_config, indent=2)

        html_template = f"""<!DOCTYPE html>
<html>
<head>
    <title>{title}</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {{
            margin: 0;
            padding: 0;
            font-family: sans-serif;
        }}
        #map {{
            width: {map_state.get('width', '100%')};
            height: {map_state.get('height', '600px')};
        }}
        .loading {{
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
            font-size: 18px;
            color: #555;
        }}
    </style>
</head>
<body>
    <div id="map">
        <div class="loading">Loading KeplerGL Map...</div>
    </div>

    <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/redux@3.7.2/dist/redux.js"></script>
    <script src="https://unpkg.com/react-redux@5.1.1/dist/react-redux.min.js"></script>
    <script src="https://unpkg.com/kepler.gl@3.0.0/umd/keplergl.min.js"></script>

    <script>
        // Initialize KeplerGL
        const {{ KeplerGl, injectComponents }} = window.KeplerGl;

        // Map configuration
        const mapConfig = {config_json};
        const mapState = {map_state_json};

        // Create KeplerGL instance
        const App = () => {{
            return React.createElement(KeplerGl, {{
                id: "map",
                width: mapState.width || "100%",
                height: mapState.height || "600px",
                mapboxApiAccessToken: undefined, // Use default map tiles
                initialUiState: mapConfig.config || {{}},
                getMapboxRef: () => {{}},
                onSaveMap: () => {{}},
                onViewStateChange: () => {{}},
                onInteractionStateChange: () => {{}}
            }});
        }};

        // Render the app
        ReactDOM.render(React.createElement(App), document.getElementById('map'));

        // Initialize with data if available
        if (mapState._layers && Object.keys(mapState._layers).length > 0) {{
            // Add layers to the map
            console.log('Adding layers:', mapState._layers);
        }}
    </script>
</body>
</html>"""

        return html_template

__init__(self, center=[37.7749, -122.4194], zoom=9.0, width='100%', height='600px', show_docs=False, read_only=False, **kwargs) special

Initialize KeplerGL map widget.

Parameters:

Name Type Description Default
center List[float]

Map center as [latitude, longitude]

[37.7749, -122.4194]
zoom float

Initial zoom level

9.0
width str

Widget width

'100%'
height str

Widget height

'600px'
show_docs bool

Whether to show documentation panel

False
read_only bool

Whether the map is read-only

False
**kwargs

Additional widget arguments

{}
Source code in anymap/keplergl.py
def __init__(
    self,
    center: List[float] = [37.7749, -122.4194],
    zoom: float = 9.0,
    width: str = "100%",
    height: str = "600px",
    show_docs: bool = False,
    read_only: bool = False,
    **kwargs,
):
    """Initialize KeplerGL map widget.

    Args:
        center: Map center as [latitude, longitude]
        zoom: Initial zoom level
        width: Widget width
        height: Widget height
        show_docs: Whether to show documentation panel
        read_only: Whether the map is read-only
        **kwargs: Additional widget arguments
    """
    super().__init__(
        center=center,
        zoom=zoom,
        width=width,
        height=height,
        **kwargs,
    )
    self.show_docs = show_docs
    self.read_only = read_only
    self._initialize_config()

add_csv(self, csv_data, layer_name='csv_layer', **kwargs)

Add CSV data to the map.

Parameters:

Name Type Description Default
csv_data Union[str, List[Dict]]

CSV data (file path or list of dictionaries)

required
layer_name str

Name for the layer

'csv_layer'
**kwargs

Additional layer configuration

{}
Source code in anymap/keplergl.py
def add_csv(
    self, csv_data: Union[str, List[Dict]], layer_name: str = "csv_layer", **kwargs
) -> None:
    """Add CSV data to the map.

    Args:
        csv_data: CSV data (file path or list of dictionaries)
        layer_name: Name for the layer
        **kwargs: Additional layer configuration
    """
    if isinstance(csv_data, str):
        # Load from file
        import pandas as pd

        df = pd.read_csv(csv_data)
        csv_data = df.to_dict("records")
    elif isinstance(csv_data, list):
        # Data is already in the correct format (list of dictionaries)
        pass
    else:
        # Convert other formats to list of dictionaries
        csv_data = [csv_data]

    # Store the data in the widget's internal data structure
    current_data = dict(self._data)
    current_data[layer_name] = {"type": "csv", "data": csv_data}
    self._data = current_data

add_data(self, data, name='dataset')

Add data to the map.

Parameters:

Name Type Description Default
data Union[Dict, List]

Data to add (GeoJSON, DataFrame, etc.)

required
name str

Name for the dataset

'dataset'
Source code in anymap/keplergl.py
def add_data(self, data: Union[Dict, List], name: str = "dataset") -> None:
    """Add data to the map.

    Args:
        data: Data to add (GeoJSON, DataFrame, etc.)
        name: Name for the dataset
    """
    # Determine data type and format
    if isinstance(data, dict) and data.get("type") == "FeatureCollection":
        # GeoJSON data
        data_type = "geojson"
    elif isinstance(data, list):
        # Array of objects (CSV-like data)
        data_type = "csv"
    else:
        # Default to geojson
        data_type = "geojson"

    # Store the data in the widget's internal data structure
    current_data = dict(self._data)
    current_data[name] = {"type": data_type, "data": data}
    self._data = current_data

add_geojson(self, geojson, layer_name='geojson_layer', **kwargs)

Add GeoJSON data to the map.

Parameters:

Name Type Description Default
geojson Union[str, Dict]

GeoJSON data (dict or file path)

required
layer_name str

Name for the layer

'geojson_layer'
**kwargs

Additional layer configuration

{}
Source code in anymap/keplergl.py
def add_geojson(
    self, geojson: Union[str, Dict], layer_name: str = "geojson_layer", **kwargs
) -> None:
    """Add GeoJSON data to the map.

    Args:
        geojson: GeoJSON data (dict or file path)
        layer_name: Name for the layer
        **kwargs: Additional layer configuration
    """
    if isinstance(geojson, str):
        # Load from file
        with open(geojson, "r") as f:
            geojson_data = json.load(f)
    else:
        geojson_data = geojson

    # Store the data in the widget's internal data structure
    current_data = dict(self._data)
    current_data[layer_name] = {"type": "geojson", "data": geojson_data}
    self._data = current_data

get_map_state(self)

Get the current map state.

Returns:

Type Description
Dict[str, Any]

Current map state dictionary

Source code in anymap/keplergl.py
def get_map_state(self) -> Dict[str, Any]:
    """Get the current map state.

    Returns:
        Current map state dictionary
    """
    return self.map_config

load_config(self, filename)

Load configuration from a file.

Parameters:

Name Type Description Default
filename str

Path to the configuration file

required
Source code in anymap/keplergl.py
def load_config(self, filename: str) -> None:
    """Load configuration from a file.

    Args:
        filename: Path to the configuration file
    """
    with open(filename, "r") as f:
        config = json.load(f)
    self.update_map_config(config)

save_config(self, filename)

Save the current configuration to a file.

Parameters:

Name Type Description Default
filename str

Path to save the configuration

required
Source code in anymap/keplergl.py
def save_config(self, filename: str) -> None:
    """Save the current configuration to a file.

    Args:
        filename: Path to save the configuration
    """
    with open(filename, "w") as f:
        json.dump(self.map_config, f, indent=2)

set_filter(self, filter_config)

Set filter configuration.

Parameters:

Name Type Description Default
filter_config Dict[str, Any]

Filter configuration

required
Source code in anymap/keplergl.py
def set_filter(self, filter_config: Dict[str, Any]) -> None:
    """Set filter configuration.

    Args:
        filter_config: Filter configuration
    """
    self.call_js_method("setFilter", filter_config)

update_map_config(self, config)

Update the map configuration.

Parameters:

Name Type Description Default
config Dict[str, Any]

New configuration to merge

required
Source code in anymap/keplergl.py
def update_map_config(self, config: Dict[str, Any]) -> None:
    """Update the map configuration.

    Args:
        config: New configuration to merge
    """

    # Deep merge the configuration
    def deep_merge(dict1, dict2):
        result = dict1.copy()
        for key, value in dict2.items():
            if (
                key in result
                and isinstance(result[key], dict)
                and isinstance(value, dict)
            ):
                result[key] = deep_merge(result[key], value)
            else:
                result[key] = value
        return result

    self.map_config = deep_merge(self.map_config, config)