1

I would like to create a scattermapbox for indonesia for various statistics (population, GDP, etc.) on a regional basis. I am working with a geopandas file from github.

The example on the plotly website creates multiple files for each layer and then uses the github link as source.

#republican counties
source = 'https://raw.githubusercontent.com/plotly/datasets/master/florida-red-data.json'  
#democrat counties
source = 'https://raw.githubusercontent.com/plotly/datasets/master/florida-blue-data.json'

My question therefore is, how can I use the pandas dataframe to create layer dict for every region and use that as a source (also colouring of each region by specific values in other dataframes). Should that not be possible at all and it is necessary to create a seperate file for each region how would I do that? My attempt (lines 16-20) doesn't seem to work

import pandas as pd
import json
import string
import plotly
from plotly.graph_objs import Scattermapbox, Layout
ID_regions = pd.read_json('https://raw.githubusercontent.com/N1x0/indonesia-geojson/master/indonesia-edit.geojson')

region_names = []

for region in ID_regions['features']:
    region_names.append(state['properties']['name'])

print(region_names)

#This shit creates json and doesn't work
def create_region_files():
    for i in range(len(ID_regions)):
        region_data = ID_regions.iloc[i,:]
        region_data.to_json(f'C:\\Users\\nicho\\Desktop\\Waste Management\\Map_Maker\\ID_regions\\{region_names[i]}.json')
        i += 1


def create_Chloropleth():
    mapbox_access_token = 'My Access Key'

    data = [
        Scattermapbox(
            lat=['45.5017'],
            lon=['-73.5673'],
            mode='markers',
        )
    ]
    layout = Layout(
        height=900,
        autosize=True,
        showlegend=False,
        hovermode='closest',
        mapbox=dict(
            layers=[
                dict(
                    sourcetype = 'geojson',
                    source = 'https://raw.githubusercontent.com/N1x0/indonesia-geojson/master/indonesia-edit.geojson',
                    type = 'fill',
                    color = 'green'
                ),
                dict(
                    sourcetype = 'geojson',
                    source = 'https://raw.githubusercontent.com/N1x0/indonesia-geojson/master/west-sulawesi.json',
                    type = ' fill',
                    color = 'red',
                )
            ],
            accesstoken=mapbox_access_token,
            bearing=0,
            center=dict(
                lat=0.7893,
                lon=113.9213
            ),
            pitch=0,
            zoom=4.5,
            style='light'
        ),
    )

    fig = dict(data=data, layout=layout)
    plotly.offline.plot(fig, filename='Chloropleth_Province_Population.html')

create_Chloropleth()

Thank you for the help!

1 Answer 1

1

Ok took me a while but i figured it all out. Big thanks to Emma Grimaldi over at Medium and Vince Pota. Their posts were what helped me through most of it. So here the answers to my own question in order:

  1. It is not necessary to create an individual file for each region. I.e. you can use a pandas dataframe to match names of the regions in the json and that'll work just fine.

with open('indonesia-en.geojson') as f: geojson = json.load(f)

def make_sources(downsample = 0):
    sources = []
    geojson_copy = copy.deepcopy(geojson['features']) # do not overwrite the original file
    for feature in geojson_copy:

        if downsample > 0:
            coords = np.array(feature['geometry']['coordinates'][0][0])
            coords = coords[::downsample]
            feature['geometry']['coordinates'] = [[coords]]

        sources.append(dict(type = 'FeatureCollection',
                            features = [feature])
                      )
    return sources

So you just extract the coordinates from the geojson and append them to a a list of dicts[{}].

  1. How to use this list to dynamically create layers:
    MAPBOX_APIKEY = "Your API Key"
    data = dict(type='scattermapbox',
                lat=lats,
                lon=lons,
                mode='markers',
                text=hover_text,
                marker=dict(size=1,
                            color=scatter_colors,
                            showscale = True,
                            cmin = minpop/1000000,
                            cmax = maxpop/1000000,
                            colorscale = colorscale,
                            colorbar = dict(
                            title='Population in Millions'
                            )
                           ),
                showlegend=False,
                hoverinfo='text'
                 )

    layers=([dict(sourcetype = 'geojson',
                  source =sources[k],
                  below="water",
                  type = 'line',    # the borders
                  line = dict(width = 1),
                  color = 'black',
                  ) for k in range(n_provinces) # where n_provinces = len(geojson['features'])
              ] +

            [dict(sourcetype = 'geojson',
                  source =sources[k],
                  type = 'fill',   # the area inside the borders
                  color = scatter_colors[k],
                  opacity=0.8
                 ) for k in range(n_provinces)  # where n_provinces = len(geojson['features'])
             ]
            )

So the solution here is too set sources = sources[k] I.e. the list with the dict of lat/long values created in make_sources()

  1. How to color the layers accordingly color=scatter_colors[k]

Using the linked example I used 3 functions

3.1 scalarmappable

#sets colors based on min and max values
def scalarmappable(cmap, cmin, cmax):
        colormap = cm.get_cmap(cmap)
        norm = Normalize(vmin=cmin, vmax=cmax+(cmax*0.10)) #vmax get's increased 10 percent because otherwise the most populous region doesnt get colored
        return cm.ScalarMappable(norm=norm, cmap=colormap)

3.2 scatter_colors

#uses matplotlib to create colors based on values and sets grey for isnan value
def get_scatter_colors(sm, df):
grey = 'rgba(128,128,128,1)'
return ['rgba' + str(sm.to_rgba(m, bytes = True, alpha = 1)) if not np.isnan(m) else grey for m in df]  

3.3 colorscale

#defines horizontal range and corresponding values for colorscale
def get_colorscale(sm, df, cmin, cmax):
    xrange = np.linspace(0, 1, len(df))
    values = np.linspace(cmin, cmax, len(df))

    return [[i, 'rgba' + str(sm.to_rgba(v, bytes = True))] for i,v in zip(xrange, values) ]

Then variables using the functions are set

#assigning values
colormap = 'nipy_spectral'
minpop = stats['population'].min()
maxpop = stats['population'].max()
sources = make_sources(downsample=0)
lons, lats = get_centers()

sm = scalarmappable(colormap, minpop, maxpop)
scatter_colors = get_scatter_colors(sm, stats['population'])
colorscale = get_colorscale(sm, stats, minpop, maxpop)
hover_text = get_hover_text(stats['population'])

So if anyone had some problems with this answer can help you progress :)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.