La_haine
La_haine

Reputation: 349

How to add legend in Basemap with Python

I am trying to put a legend in my world map. Every point is a different kind of devices from a different tweet. World map

Here is my code:

import geocoder
import json
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt

def openJSON(file, path):
    with open(path + file + '.json', 'r') as fp:
        data = json.load(fp)
        return data


def App_users(data):
    android_users = []
    iphone_users = []
    other_users = []

    #3 types of users: Android, Iphone and others:
    for a, b, c, d in data:
        if "Twitter for Android" in d:
            android_users.append([a, b])
        elif "Twitter for iPhone" in d:
            iphone_users.append([a, b])
        else:
            other_users.append([a, b])

    data = (android_users, iphone_users, other_users)
    return data


if __name__ == '__main__':

    posXY_add = []

    for d in data[0:50]:
        if d["user"]["location"] != None:
            g = geocoder.google(d["user"]["location"])
            if g.latlng != None:
                a = g.latlng + [g.address] + [str(d["source"])]
                posXY_add.append(a)

    data = App_users(posXY_add)

    map = Basemap(llcrnrlat=-70, urcrnrlat=70,
                    llcrnrlon=-180, urcrnrlon=180, epsg=3395)
    map.arcgisimage(service='ESRI_Imagery_World_2D', xpixels = 1500, verbose= True)

    colors = ['r', 'g', 'b']
    increment = 0

    for app in data:
        for item in app:
            if len(item) == 2:
                lat, lon = item[0], item[1]
                x, y = map(lon, lat)
                map.plot(x, y, colors[increment] + 'o')
        increment += 1


    plt.title("Geo-position Twitter Devices")
    plt.show()

Have You any suggests to improve my map? Different colors, different map or else? I am using Python 2.7 by Pycharm. My sample data is:

([[21.8974003, 83.39496319999999], [40.2671941, -86.1349019], [10.4805937, -66.90360629999999]], [[50.719164, -1.880769], [37.0903748, -94.5134078], [44.9862701, -93.39398279999999], [47.6062095, -122.3320708], [-27.4697707, 153.0251235], [20.593684, 78.96288]], [[43.2648545, -79.9492978], [39.1767262, -94.4867155], [33.7489954, -84.3879824], [39.7392358, -104.990251], [38.8761634, -77.0337777], [41.0082376, 28.9783589], [36.0753128, -95.95646269999999], [36.0595387, -95.90582429999999], [29.7604267, -95.3698028], [21.3014947, 106.6291304], [21.3014947, 106.6291304], [-16.6868982, -49.2648114], [10.4805937, -66.90360629999999], [45.037149, -92.825929], [33.760818, -78.967556], [45.49340369999999, -73.82329179999999], [39.750545, 37.0150217]])

Upvotes: 1

Views: 3451

Answers (2)

Brandon Molyneaux
Brandon Molyneaux

Reputation: 1763

Legend part: it's the same way you would put a legend into a plot - simply call plt.legend() with m.plot() having the label argument. So, in your case it would be:

handle_dict = {
    "Andriod" : 0,
    "iPhone" : 0,
    "Other" : 0
}
colors = ['r', 'g', 'b']
increment = 0

for app in data:
    for item in app:
        if len(item) == 2:
            lat, lon = item[0], item[1]
            x, y = map(lon, lat)
            map.plot(x, y, colors[increment] + 'o', label = 
                handle_dict[type_phone] if handle_dict[type_phone] == 0
                else "_no-legend_")
            handle_dict[type_phone] += 1
    increment += 1

plt.legend()
plt.title("Geo-position Twitter Devices")
plt.show()

You'd also have to modify your code to identify the type of phone that is being plotted (hence the variable type_phone).

Here's the link to the documentation regarding legends to modify the legend.

Making the map better: Personally, I like to use map.shadedrelief() for these world views - it's not as dark as map.bluemarble() and you can easily see the points better. There's really no need for the map.arcgisimage() argument here because you have a world view rather than a zoomed in view - it'll generate your map a bit quicker if you use the built in function. I'd also add the markeredgewidth argument to map.plot() to make the marker edge width to be something other than zero because right now your points look like they're blending in with the background. It'll make your dots pop out more.

Oh - also take time out to upgrade to Python 3 if you're able to.

Upvotes: 1

La_haine
La_haine

Reputation: 349

I have just solved the issue with a trick. An iteration on my code on "a"; in this way I just plot the first label of the category. In code:

handles = [("Android",None), ("iPhone",None), ("Other devices",None)]
colors = ['r', 'g','b']
increment = 0
for app in data:
    a = 0
    for item in app:
        if len(item) == 2:
            lat, lon = item[0], item[1]
            x, y = map(lon, lat)
            map.plot(x, y, colors[increment] + 'o', alpha=0.8, markersize=0.1, label=handles[increment][a])
            a = 1
    increment += 1
plt.legend(loc='lower left', shadow=True)

Upvotes: 0

Related Questions