def plot_kepler(layers, names, config=None):
    """
    Produces a kepler plot with data specified in layers. 
    
    Arguments
    ---------
    layers (list): a list of geodataframes to add as kepler data in order of top to bottom layers.
    names (list) : a list of strings specifyig names of data layers in kepler. 
    config (dict) : A kepler config dictionary. 
    
    Returns 
    -------
    keplergl.keplergl.KeplerGl 
        A kepler plot with data layers. 
        
    Examples
    --------
    TODO
    """
    # intialize a base kepler plot
    plot = KeplerGl(height=500)

    index = 0
    for layer in layers:
        # add data layer to kepler plot
        plot.add_data(data=layer, name=names[index])

        # increment index
        index += 1

    # check if a config is provided
    if config != None:
        plot.config = config

    return plot
Ejemplo n.º 2
0
def create_map_for_user(dict_m):
    """
    Creates the map for a single user or several users in the db.

    Parameters
    ----------
    dict_m : dictionary
        Dictionary containing the users gps data

    Returns
    ----------
    keplergl map
        A map object containing all users points in the map. Can be printed
        with print(map) or saved to file via map.save_to_html(file_name=your_file_name)
    """

    try:
        from keplergl import KeplerGl
        map_to_print = KeplerGl()
        for user in dict_m:
            df_map = dict_m[user]
            df_pp = pd.DataFrame(df_map, columns=["latitude", "longitude"])
            map_to_print.add_data(data=df_pp, name=user)
        return map_to_print

    except:
        print("Kepler is not instaled!")
        print(
            "Please install kepler if you wish to generate map visualizations."
        )
def write_html(geojson_file, data_id, output_html, config, title):
    """Write Kepler.gl HTML and update its content"""
    # Lazy load non-standard dependencies to play nicely in cases
    # when only interface description is requested and the module
    # actually does not run.
    try:
        # pylint: disable=import-outside-toplevel
        from keplergl import KeplerGl
        from in_place import InPlace
    except ImportError as error:
        gs.fatal(
            _("Missing mandatory keplergl or in_place dependencies: {error}").
            format(error=error))

    # Useful to examine the resulting configuration
    # print("Using configuration (JSON syntax):")
    # print(json.dumps(config, indent=2))
    kepler = KeplerGl(config=config)
    kepler.add_data(data=open(geojson_file).read(), name=data_id)
    kepler.save_to_html(file_name=output_html)

    # Add map title and creator
    with InPlace(output_html) as file:
        for line in file:
            line = line.replace(
                "<title>Kepler.gl</title>",
                f"<title>{title} &ndash; GRASS GIS Kepler.gl</title>",
            )
            line = line.replace("Kepler.gl Jupyter", title)
            file.write(line)
Ejemplo n.º 4
0
def main():
    column_short = sys.argv[1]
    column_long = sys.argv[2]
    config_file = "keplergl_config.json"
    data_id = "buildings"
    config = read_configuration(config_file,
                                label="Buildings",
                                data_id=data_id,
                                color_column=column_long)
    print("Using configuration (JSON syntax):")
    print(json.dumps(config, indent=2))
    kepler = KeplerGl(config=config)
    kepler.add_data(data=open("buildings.geojson").read(), name=data_id)
    output = f"keplergl_{column_short}.html"
    kepler.save_to_html(file_name=output)

    name = column_long.replace("_", " ")

    # Add map title and creator
    with InPlace(output) as file:
        for line in file:
            line = line.replace(
                "<title>Kepler.gl</title>",
                f"<title>{name} &ndash; Campus Research Reopening Map"
                " by NCSU CGA</title>",
            )
            line = line.replace("Kepler.gl Jupyter",
                                "Kepler.gl Map by NCSU CGA")
            file.write(line)
Ejemplo n.º 5
0
    def create_map(self, filename='airport_map'):
        flight_map = KeplerGl(height=500, width=800)

        flight_feature_collection = {
            'type': 'FeatureCollection',
            'features': self.flight_list
        }

        large_airport_feature_collection = {
            'type':
            'FeatureCollection',
            'features': [
                airport for airport in self.airport_list
                if airport['properties']['facility_type'] == 'large_airport'
            ]
        }

        medium_airport_feature_collection = {
            'type':
            'FeatureCollection',
            'features': [
                airport for airport in self.airport_list
                if airport['properties']['facility_type'] == 'medium_airport'
            ]
        }

        small_airport_feature_collection = {
            'type':
            'FeatureCollection',
            'features': [
                airport for airport in self.airport_list
                if airport['properties']['facility_type'] == 'small_airport'
            ]
        }

        flight_map.add_data(data=flight_feature_collection, name='flights')
        flight_map.add_data(data=large_airport_feature_collection,
                            name='large_airports')
        flight_map.add_data(data=medium_airport_feature_collection,
                            name='medium_airports')
        flight_map.add_data(data=small_airport_feature_collection,
                            name='small_airports')

        flight_map.save_to_html(file_name=f'{filename}.html')
        return flight_map
Ejemplo n.º 6
0
def make_map(network):
    run_vehicle_position, queue_vehicle_position, closed_link_position = extract_vehicle_locations(network)
    # make gdf
    queue_vehicle_position_gdf = make_gdf(queue_vehicle_position)
    run_vehicle_position_gdf = make_gdf(run_vehicle_position)
    closed_link_gdf = add_closed_links(closed_link_position)
    # make map
    with open('keplergl_config.json') as jsonfile:
        map_config = json.load(jsonfile)
    map_vehicles = KeplerGl(height=400, config=map_config)
    # map_vehicles = KeplerGl(height=400)
    map_vehicles.add_data(data=queue_vehicle_position_gdf, name='queue vehicles')
    map_vehicles.add_data(data=run_vehicle_position_gdf, name='run vehicles')
    map_vehicles.add_data(data=closed_link_gdf, name='closed_links')
    return map_vehicles
Ejemplo n.º 7
0
def showTrajectoriesFromZones(origin_id, dest_id, direct):
    int_shapefile = gpd.read_file(direct + "TAZ/InternalCentroidZones.shp") # change ./.... to rootdir for DB
    ext_shapefile = gpd.read_file(direct + "TAZ/ExternalCentroidZones.shp") # change ./.... to rootdir for DB

    df = pd.read_csv("trajectories_condensed.csv")
    gdf_origins = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['Origin X'], df['Origin Y']))

    df = pd.read_csv("trajectories_condensed.csv")
    gdf_dests = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['Dest X'], df['Dest Y']))

    int_trajectories_origins = clusterByZone(gdf_origins, int_shapefile, merge=False)
    int_trajectories_dests = clusterByZone(gdf_dests, int_shapefile, merge=False)
    
    matching_trajectories = trajectoriesFromZones(int_trajectories_origins, int_trajectories_dests, origin_id, dest_id)
    df = pd.read_csv("trajectories_condensed.csv")
    
    chosen_zones_map = KeplerGl(height=500)
    int_zones = clusterByZone(gdf_origins, int_shapefile, merge=True)
    chosen_zones_map.add_data(data=df, name='Trajectories')
    chosen_zones_map.add_data(data=matching_trajectories, name='Matching Trajectories')
    chosen_zones_map.add_data(data=int_zones, name='Internal Zones')
    
    chosen_zones_map.save_to_html(file_name="chosen_zones_map.html")
    return chosen_zones_map
import bokeh
hv.save(baum_map, 'frankfurter_baum.html', backend='bokeh')

# In[24]:

# In[13]:

from keplergl import KeplerGl
import pandas as pd
import geopandas as gpd

# In[22]:

map = KeplerGl(height=800)
map.add_data(data=df, name="test")

# mape = KeplerGl(height=500)

#

# In[23]:

map

# In[25]:

config = map.config

# In[29]:
Ejemplo n.º 9
0
        sign.append(0)

df['Sign'] = sign

latitude_layer = []
longitude_layer = []
latitude = 41.377491
longitude = 64.585262
for i in range(len(df)):
    if (df['Sign'][i] == 1):
        latitude_layer.append(latitude)
        longitude_layer.append(longitude)
    else:
        latitude_layer.append(df['Latitude'][i])
        longitude_layer.append(df['Longitude'][i])

df['Latitude_Layer'] = latitude_layer
df['Longitude_Layer'] = longitude_layer

from keplergl import KeplerGl
import geopandas as gpd
map_1 = KeplerGl(height=500)
#df=pd.read_csv('df2001.csv')
df['Longitude'] = pd.to_numeric(df['Longitude'])
df['Latitude'] = pd.to_numeric(df['Latitude'])
gdf = gpd.GeoDataFrame(df,
                       geometry=gpd.points_from_xy(df.Longitude, df.Latitude))
map_1.add_data(data=gdf)

map_1.save_to_html(file_name='dark2009.html')
Ejemplo n.º 10
0
airport_df.drop(labels='coordinates', axis='columns', inplace=True)

airport_df.dropna(axis='index', subset=['iata'], inplace=True)
airport_df.reset_index(drop=True, inplace=True)
airport_df

# + colab={"base_uri": "https://localhost:8080/", "height": 0} colab_type="code" executionInfo={"elapsed": 32918, "status": "ok", "timestamp": 1574653714933, "user": {"displayName": "So Negishi", "photoUrl": "", "userId": "14957100293746809516"}, "user_tz": 300} id="APOoXNf75-LT" outputId="dbb1fcc1-b527-482f-df8b-e43e5617b812"
airport_df[airport_df.iata == 'JFK']

# + colab={"base_uri": "https://localhost:8080/", "height": 0} colab_type="code" executionInfo={"elapsed": 32915, "status": "ok", "timestamp": 1574653714934, "user": {"displayName": "So Negishi", "photoUrl": "", "userId": "14957100293746809516"}, "user_tz": 300} id="tS9Pv_2K5-LV" outputId="35d38b54-d0b7-4ec0-8e82-56b8bb1df5a0"
airport_map = KeplerGl(height=900, width=800)
airport_map_data = airport_df[[
    'name', 'latitude', 'longitude', 'facility_type'
]]
airport_map.add_data(
    data=airport_map_data[airport_map_data.facility_type == 'large_airport'],
    name='large_airports')
airport_map.add_data(
    data=airport_map_data[airport_map_data.facility_type == 'medium_airport'],
    name='medium_airports')
airport_map.add_data(
    data=airport_map_data[airport_map_data.facility_type == 'small_airport'],
    name='small_airports')
airport_map.save_to_html(file_name='./visualization/airport_map.html')
# airport_map

# + [markdown] colab_type="text" id="uJf8Ce225-LY"
# ## 2. Get flight info

# + colab={"base_uri": "https://localhost:8080/", "height": 0} colab_type="code" executionInfo={"elapsed": 39951, "status": "ok", "timestamp": 1574653721974, "user": {"displayName": "So Negishi", "photoUrl": "", "userId": "14957100293746809516"}, "user_tz": 300} id="IN6ZY7qS5-LY" outputId="9b70a9cf-0857-4370-f401-d81fc28e2bbb"
flight_df = pd.read_csv('./raw_data/266694930_T_ONTIME_REPORTING.csv',
Ejemplo n.º 11
0
class Visualize:
    """Quickly visualize data in browser over Mapbox tiles with the help of the AMAZING kepler.gl.
    """
    def __init__(self,
                 data=None,
                 names=None,
                 read_only=False,
                 api_key=None,
                 style=None):
        """Visualize data using kepler.gl

        Args:
            data Optional[Union[List[]]]:
                either None, a List of data objects, or a single data object. If
                data is not None, then Visualize(data) will perform all steps,
                including rendering and opening a browser.
        """
        super(Visualize, self).__init__()

        if api_key is not None:
            self.MAPBOX_API_KEY = api_key
        else:
            self.MAPBOX_API_KEY = os.getenv('MAPBOX_API_KEY')
            msg = 'Warning: api_key not provided and MAPBOX_API_KEY '
            msg += 'environment variable not set.\nMap may not display.'
            if self.MAPBOX_API_KEY is None:
                print(msg)

        config = self.config(style=style)
        self.map = KeplerGl(config=config)

        if data is not None:
            self.add_data(data=data, names=names)
            self.html_path = self.render(read_only=read_only)

    def config(self, style=None):
        """Load kepler.gl config and insert Mapbox API Key"""

        config_file = resource_filename('keplergl_cli', 'keplergl_config.json')

        # First load config file as string, replace {MAPBOX_API_KEY} with the
        # actual api key, then parse as JSON
        with open(config_file) as f:
            text = f.read()

        text = text.replace('{MAPBOX_API_KEY}', self.MAPBOX_API_KEY)
        keplergl_config = json.loads(text)

        # If style_url is not None, replace existing value
        standard_styles = [
            'streets',
            'outdoors',
            'light',
            'dark',
            'satellite',
            'satellite-streets',
        ]
        if style is not None:
            style = style.lower()
            if style in standard_styles:
                # Just change the name of the mapStyle.StyleType key
                keplergl_config['config']['config']['mapStyle'][
                    'styleType'] = style
            else:
                # Add a new style with that url
                d = {
                    'accessToken': self.MAPBOX_API_KEY,
                    'custom': True,
                    'id': 'custom',
                    'label': 'Custom map style',
                    'url': style
                }
                keplergl_config['config']['config']['mapStyle']['mapStyles'][
                    'custom'] = d
                keplergl_config['config']['config']['mapStyle'][
                    'styleType'] = 'custom'

        # Remove map state in the hope that it'll auto-center based on data
        # keplergl_config['config']['config'].pop('mapState')
        return keplergl_config['config']

    def add_data(self, data, names=None):
        """Add data to kepler map

        Data should be either GeoJSON or GeoDataFrame. Kepler isn't aware of the
        geojson or shapely package, so if I supply an object from one of these
        libraries, first convert it to a GeoJSON dict.
        """
        # Make `data` iterable
        if not isinstance(data, list):
            data = [data]

        # Make `names` iterable and of the same length as `data`
        if isinstance(names, list):
            # Already iterable, make sure they're the same length
            msg = 'data and names are iterables of different length'
            assert len(data) == len(names), msg
        else:
            # `names` not iterable, make sure it's the same length as `data`
            name_stub = 'data' if names is None else names
            names = [f'{name_stub}_{x}' for x in range(len(data))]

        for datum, name in zip(data, names):
            if any(isinstance(datum, c) for c in SHAPELY_GEOJSON_CLASSES):
                datum = dict(mapping(datum))

            self.map.add_data(data=datum, name=name)

    def render(self, open_browser=True, read_only=False):
        """Export kepler.gl map to HTML file and open in Chrome
        """
        # Generate path to a temporary file
        path = os.path.join(tempfile.mkdtemp(), 'vis.html')
        self.map.save_to_html(file_name=path, read_only=read_only)

        # Open saved HTML file in new tab in default browser
        webbrowser.open_new_tab('file://' + path)

        return path
Ejemplo n.º 12
0
def generate_map(query_results: List[QueryResult],
                 height: int = 500,
                 config: Optional[Dict] = KEPLER_DEFAULT_CONFIG,
                 column: Optional[Union[str, List[str]]] = None,
                 weights: Optional[List[int]] = None,
                 clusters: Optional[Union[bool, float]] = False) -> KeplerGl:
    """
    Returns Kepler map combining multiple query results.
    :param query_results: List of QueryResult objects
    :param height: Height of the map
    :param config: Kepler config dict to use for styling the map.
    :param column: Name of the field or JSON column in each QueryResult to plot.
        Note that if you have calculated some statistics of a JSON field in
        QueryResult, the dataframe is flattened already, and you must use only
        the name of the field inside the JSON. You may provide a list of names
        (same length as query_results) if you wish to plot different columns
        in different dataframes.
    :param weights: Optional. If present, will also calculate a weighted sum
        of any H3 datasets. Must have the same length as query_results. If a dataset
        has no hex column, it will not be included.
    :param clusters: If True, will also calculate spatial clusters and outliers for
        the weighted sum. You may specify the statistical significance threshold
        by specifying a float instead. The default threshold is 0.05. If weights is
        not present, does nothing.
    """

    config = deepcopy(config)
    center = QueryResult.get_center_of_all(query_results)
    zoom = QueryResult.get_zoom_of_all(query_results)
    has_strings = list(
        filter(lambda qr: qr.geom_type in ['MultiLineString', 'LineString'],
               query_results))

    if center:
        config['config']['mapState'].update(**center)
    if zoom:
        config['config']['mapState']['zoom'] = zoom
    if has_strings:
        config['config']['visState']['layerBlending'] = 'additive'

    map_1 = KeplerGl(height=height)

    # empty the layer config, add point or hex layer, depending on presence of hex column
    config["config"]["visState"]["layers"] = []
    for i, qr in enumerate(query_results, start=1):
        if not qr.is_empty:
            name = qr.name if qr.name is not None else f'data_{i}'
            map_1.add_data(data=qr.gdf, name=name)
            hex_column = next(
                (col for col in qr.gdf.columns if col.startswith("hex")),
                False)
            if hex_column:
                # add hex layer
                hex_layer_config = deepcopy(KEPLER_DEFAULT_HEX_LAYER_CONFIG)
                hex_layer_config["id"] = f"{hex_column}_{name}"
                hex_layer_config["config"]["dataId"] = name
                hex_layer_config["config"]["label"] = f"{hex_column}_{name}"
                hex_layer_config["config"]["columns"]["hex_id"] = hex_column
                # Also column that the user wishes to plot may change
                if column:
                    # Allow plotting different columns for different queries, or same column for all
                    data_column = column if isinstance(column,
                                                       str) else column[i - 1]
                    hex_layer_config["visualChannels"]["colorField"][
                        "name"] = data_column
                    if qr.gdf[data_column].dtype == "float64":
                        hex_layer_config["visualChannels"]["colorField"][
                            "type"] = "real"
                    elif qr.gdf[data_column].dtype == "int64":
                        hex_layer_config["visualChannels"]["colorField"][
                            "type"] = "integer"
                config["config"]["visState"]["layers"].append(hex_layer_config)
            else:
                # add point layer for raw data
                layer_config = deepcopy(KEPLER_DEFAULT_LAYER_CONFIG)
                layer_config["id"] = name
                layer_config["config"]["dataId"] = name
                layer_config["config"]["label"] = name
                config["config"]["visState"]["layers"].append(layer_config)
    # Generate a new queryresult summing the hex layers if weights are present
    if weights:
        if isinstance(column, str):
            column = [column] * len(weights)
        sum_layer = generate_sum_layer(query_results, column, weights)
        name = sum_layer.name
        map_1.add_data(data=sum_layer.gdf, name=name)
        hex_column = next(
            (col for col in sum_layer.gdf.columns if col.startswith("hex")),
            False)

        # Hide the individual layers if sum is displayed
        for layer_config in config["config"]["visState"]["layers"]:
            layer_config["config"]["isVisible"] = False
        # add hex layer
        hex_layer_config = deepcopy(KEPLER_DEFAULT_HEX_LAYER_CONFIG)
        hex_layer_config["id"] = name
        hex_layer_config["config"]["dataId"] = name
        hex_layer_config["config"]["label"] = name
        hex_layer_config["config"]["columns"]["hex_id"] = hex_column
        hex_layer_config["visualChannels"]["colorField"]["name"] = name
        hex_layer_config["visualChannels"]["colorField"]["type"] = "real"
        config["config"]["visState"]["layers"].append(hex_layer_config)

        if clusters:
            if isinstance(clusters, float):
                cluster_gdf = generate_clusters(gdf=sum_layer.gdf,
                                                col="sum",
                                                alpha=clusters)
            else:
                cluster_gdf = generate_clusters(gdf=sum_layer.gdf, col="sum")
            name = 'clusters'
            map_1.add_data(data=cluster_gdf, name=name)
            hex_column = next(
                (col for col in cluster_gdf.columns if col.startswith("hex")),
                False)
            # add cluster layer
            cluster_layer_config = deepcopy(
                KEPLER_DEFAULT_CLUSTER_LAYER_CONFIG)
            cluster_layer_config["id"] = name
            cluster_layer_config["config"]["dataId"] = name
            cluster_layer_config["config"]["label"] = name
            cluster_layer_config["config"]["columns"]["hex_id"] = hex_column
            cluster_layer_config["config"]["isVisible"] = False
            config["config"]["visState"]["layers"].append(cluster_layer_config)
            # filter cluster layer so that only statistically significant clusters
            # are displayed by default
            config["config"]["visState"]["filters"].append(
                KEPLER_DEFAULT_CLUSTER_FILTER_CONFIG)

    map_1.config = config
    return map_1
from keplergl import KeplerGl 


# df needs to contain 'latitude' and 'longitude' columns
map_ = KeplerGl(height=700)
map_.add_data(df, 'Data')
map_.save_to_html(file_name='try.html')

Ejemplo n.º 14
0
from keplergl import KeplerGl

map1 = KeplerGl(height=600)
map1.add_data(data=df)
map1

Ejemplo n.º 15
0
                    "pk.eyJ1IjoianVzdHN0YW4iLCJhIjoiY2tlc3hncWJ4MWh3cTJ4cXY5ZmsxdmoyYiJ9.LHycdQ3Il_MDxeW8JfiNWw",
                    "custom": True,
                    "icon":
                    "https://api.mapbox.com/styles/v1/mapbox/satellite-streets-v11/static/-122.3391,37.7922,9,0,0/400x300?access_token=pk.eyJ1IjoianVzdHN0YW4iLCJhIjoiY2tlc3hncWJ4MWh3cTJ4cXY5ZmsxdmoyYiJ9.LHycdQ3Il_MDxeW8JfiNWw&logo=false&attribution=false",
                    "id": "satellite-streets",
                    "label": "Mapbox Satellite Streets",
                    "url": "mapbox://styles/mapbox/satellite-streets-v11"
                }
            }
        }
    }
}
## 1st
df = pd.read_csv("data/olist_orders_geo.csv")

map_1 = KeplerGl(height=600, width=800, data={"data_1": df}, config=config)
map_1.add_data(data=df, name='data_1')
map_1.data
print(df.head())

gdf = gpd.GeoDataFrame(df,
                       geometry=gpd.points_from_xy(df.cust_lng, df.cust_lat))

viz = Visualize(gdf, api_key=MAPBOX_API_KEY)

viz.render(open_browser=True, read_only=False)

map_1.save_to_html(data={'data_1': df},
                   config=config,
                   file_name='olist-order-geo-config.html')
Ejemplo n.º 16
0
            "styleType":
            "dark",
            "topLayerGroups": {},
            "visibleLayerGroups": {
                "label": True,
                "road": True,
                "border": False,
                "building": True,
                "water": True,
                "land": True,
                "3d building": False
            },
            "threeDBuildingColor":
            [9.665468314072013, 17.18305478057247, 31.1442867897876],
            "mapStyles": {}
        }
    }
}

# COMMAND ----------

# DBTITLE 1,Plot Data
from keplergl import KeplerGl

m1 = KeplerGl(config=plot1_conf)
m1.add_data(data=total_spend_pd[["id", "spend", "wkt"]], name="spend")

displayKepler(m1, 1000)

# COMMAND ----------
Ejemplo n.º 17
0
import pandas as pd
import os
from six.moves import urllib

import pandas as pd  # importing the Pandas Library as 'pd'
from keplergl import KeplerGl  # importing KeplerGl
import geopandas as gpd  # importing geopandas as 'gpd'

# datasheet
dataset = pd.read_csv("poluition_map.csv",
                      encoding='utf8',
                      delimiter=',',
                      engine='python')

dataset.head()

#Create a basemap
map = KeplerGl(height=600, width=800)

# Create a geodataframe
gdf = gpd.GeoDataFrame(dataset,
                       geometry=gpd.points_from_xy(dataset.latitude,
                                                   dataset.longitude))
#make sure that your latitude and longitude are named as they are in your csv

map.add_data(data=gdf, name="IQA")  # add geoenabled dataframe to map

map.save_to_html(file_name='GeoViz.html')

map
Ejemplo n.º 18
0
def generate_vis():
  config = {
    "version": "v1",
    "config": {
      "visState": {
        "filters": [],
        "layers": [
          {
            "id": "rfnq31gn",
            "type": "grid",
            "config": {
              "dataId": "income",
              "label": "Point",
              "color": [
                255,
                203,
                153
              ],
              "columns": {
                "lat": "Lat",
                "lng": "Lon"
              },
              "isVisible": True,
              "visConfig": {
                "opacity": 0.89,
                "worldUnitSize": 15,
                "colorRange": {
                  "name": "Global Warming",
                  "type": "sequential",
                  "category": "Uber",
                  "colors": [
                    "#5A1846",
                    "#900C3F",
                    "#C70039",
                    "#E3611C",
                    "#F1920E",
                    "#FFC300"
                  ]
                },
                "coverage": 1,
                "sizeRange": [
                  0,
                  1000
                ],
                "percentile": [
                  0,
                  100
                ],
                "elevationPercentile": [
                  0,
                  100
                ],
                "elevationScale": 5,
                "colorAggregation": "average",
                "sizeAggregation": "average",
                "enable3d": True
              },
              "hidden": False,
              "textLabel": [
                {
                  "field": None,
                  "color": [
                    255,
                    255,
                    255
                  ],
                  "size": 18,
                  "offset": [
                    0,
                    0
                  ],
                  "anchor": "start",
                  "alignment": "center"
                }
              ]
            },
            "visualChannels": {
              "colorField": {
                "name": "Median",
                "type": "integer"
              },
              "colorScale": "quantile",
              "sizeField": {
                "name": "Median",
                "type": "integer"
              },
              "sizeScale": "linear"
            }
          }
        ],
        "interactionConfig": {
          "tooltip": {
            "fieldsToShow": {
              "97ap1ofch": [
                {
                  "name": "id",
                  "format": None
                },
                {
                  "name": "State_Code",
                  "format": None
                },
                {
                  "name": "State_Name",
                  "format": None
                },
                {
                  "name": "State_ab",
                  "format": None
                },
                {
                  "name": "County",
                  "format": None
                }
              ]
            },
            "compareMode": False,
            "compareType": "absolute",
            "enabled": True
          },
          "brush": {
            "size": 0.5,
            "enabled": False
          },
          "geocoder": {
            "enabled": False
          },
          "coordinate": {
            "enabled": False
          }
        },
        "layerBlending": "normal",
        "splitMaps": [],
        "animationConfig": {
          "currentTime": None,
          "speed": 1
        }
      },
      "mapState": {
        "bearing": 24,
        "dragRotate": True,
        "latitude": 30.067203168518454,
        "longitude": -128.1037388392268,
        "pitch": 50,
        "zoom": 3.379836309981588,
        "isSplit": False
      },
      "mapStyle": {
        "styleType": "dark",
        "topLayerGroups": {},
        "visibleLayerGroups": {
          "label": True,
          "road": True,
          "border": False,
          "building": True,
          "water": True,
          "land": True,
          "3d building": False
        },
        "threeDBuildingColor": [
          9.665468314072013,
          17.18305478057247,
          31.1442867897876
        ],
        "mapStyles": {}
      }
    }
  }

  m = KeplerGl()
  m.config = config
  m.add_data(data=import_data(), name="income")
  m.save_to_html(file_name="index.html")