[PYTHON] Beginners of Google Maps API and Twitter API made "tweet map"

Introduction

If I knew when, where, and what I tweeted, I thought it would be fun like a life log, so I made a "tweet map".

This is my first time to touch both Google Maps API and Twtter API. Thank you for your help on various sites. .. .. ..

スクリーンショット 2019-11-25 14.14.55.png ⬆️ This is when I ride a bicycle on the Shimanami Kaido (It's fun to know where and what you're doing! It's personal information!)

0. Development environment

PC: MacBook Air (Retina, 13-inch, 2018) OS: macOS Mojave (ver 10.14.1) Processor: 1.6 GHz Intel Core i5 Memory: 16 GB 2133 MHz LPDDR3 Editor: Visual Studio Code

1. Preparation

This time, we will download the movement history from the location history of Google Map and use it. In addition, the content of the tweet is acquired using the Twitter API. Data download and registration are required for each.

Get location history

For how to get the location history, refer to here. Download Google Map History (timeline)

Extract Google Maps action log

How to register Google Maps API

For the registration method required when using the Google Masp API, refer to here. I tried using the Google Maps API

How to register Twitter API

For the registration method of Twitter API, refer to here. Summary of steps from Twitter API registration (account application method) to approval

Tweet data preparation

Since the location history data is in json format and it seems convenient to match the file format, prepare the tweet data in json format (tweet_timeline.json) as well.

(This time I wanted to use a library called tweepy, so I wrote it in python.)

get_tweet_data.py


import tweepy
import json
import time
import calendar


#Consumer key and access token settings for using Twitter API
Consumer_key = '<API key obtained by applying for Twitter API registration>'
Consumer_secret = '<Consumer obtained by applying for Twitter API registration_secret>'
Access_token = '<Access obtained by applying for Twitter API registration_token>'
Access_secret = '<Access obtained by applying for Twitter API registration_secret>'

#Authentication
auth = tweepy.OAuthHandler(Consumer_key, Consumer_secret)
auth.set_access_token(Access_token, Access_secret)

api = tweepy.API(auth, wait_on_rate_limit=True)


#Tweet data array
tweet_data = []

#Acquisition account Account name@Enter the name excluding
user = "******"

#json data creation
for tweet in tweepy.Cursor(api.user_timeline, screen_name=user, exclude_replies=True, include_entities=True).items():

    #Convert twitter API tweet time to UNIX
    tweet_utc_time = time.strptime(
        str(tweet.created_at), "%Y-%m-%d %H:%M:%S")
    tweet_unix_time = calendar.timegm(tweet_utc_time)

    #If there is an image, add the URL element of the image
    if 'media' in tweet.entities:
        for media in tweet.entities['media']:
            tweet_image_url = media['media_url_https']

            #Added image element to tweet data array
            tweet_data.append({
                "id": tweet.id, "created_at": tweet_unix_time, "text": tweet.text,
                "fav": tweet.favorite_count, "RT": tweet.retweet_count, "image": tweet_image_url
            })

    else:
        #Add element to tweet data array
        tweet_data.append({
            "id": tweet.id, "created_at": tweet_unix_time, "text": tweet.text,
            "fav": tweet.favorite_count, "RT": tweet.retweet_count
        })

tweet_dict = {"timeline": tweet_data}

#json file name
fw = open('tweet_timeline.json', 'w')
#json file output json.Write to a file with the dump function
json.dump(tweet_dict, fw, indent=4, ensure_ascii=False)

Since the Twitter API can take time in a special format, it is converted to Unix time to match the location history, and the image data is also summarized in a json file in an easy-to-use format.

2. Map Tweet to Google Map

After that, use the prepared location history and Tweet data to map the coordinates and Tweet data, and you're done. Since we use GoogleMapsAPI, we use javascript, html, css.

Thank you very much for your help on this site. .. .. It is almost a copy level. .. Place markers from json data with Google Maps API

sample.js


const START_DAY = '2019/4/7';
const END_DAY = '2019/4/8';
const POINTS = 1;

var date;
var ready = { api: false, ajax: false };
var map;
var mapData;
var mapOptions = {
    center: { //Map latitude and longitude
        lat: 35.700000,
        lng: 139.772000
    },
    zoom: 17, //Map magnification
    scrollwheel: false, //Whether to scale by wheel operation
    mapTypeControl: false, //Whether to show map switching controls
    streetViewControl: false //Whether to show Street View controls
}
var latlngs = [];
var tweetdata;

var infoWindowIndex = [];

var startDay = new Date(START_DAY);
var unixTimestampstartDay = Math.round(startDay.getTime());
console.log(unixTimestampstartDay)

var endDay = new Date(END_DAY);
var unixTimestampendDay = Math.round(endDay.getTime())
console.log(unixTimestampendDay)

var aveLat = 0;
var aveLng = 0;


$(function () {
    $.ajax({
        url: 'tweet_timeline.json',
        dataType: 'json',
        cache: false
    })
        .then(
            function (data) {
                console.log('I succeeded in getting the Twitter timeline.');
                tweetData = data["timeline"];
                ready['ajax'] = true;

            },
            function () {
                console.log('Failed to get the Twitter timeline.');
            }
        );
});

$(function () {
    $.ajax({
        url: 'Location history.json',
        dataType: 'json',
        cache: false
    })
        .then(
            function (data) {
                console.log('You have succeeded in acquiring location information.');
                mapData = data["locations"];
                ready['ajax'] = true;

                generate_map();
            },
            function () {
                console.log('Failed to get the location information.');
            }
        );
});


/**
 *What to do after the Google Maps API is ready
 */
function api_ready() {
    ready['api'] = true;
    generate_map();
}

/**
 *Generate a map
 */
function generate_map() {
    if (ready['api'] && ready['ajax']) {
        map = new google.maps.Map(document.getElementById('map'), {
            //Zoom level
            zoom: 10,
            //Center point latitude / longitude
            center: new google.maps.LatLng(mapData[0].latitudeE7 * 0.0000001, mapData[0].longitudeE7 * 0.0000001),
            //Distance scale display
            scaleControl: true,
            //Map type
            mapTypeId: google.maps.MapTypeId.ROADMAP

        });
        add_marker();
        generate_polyline();
    }
}

/**
 *Add markers to the map
 */
function add_marker() {
    var markerNum = 0;
    var j = 0;

    var infoWindowNum = 0;
    for (var i = 0; i < mapData.length; i += POINTS) {
        var item = mapData[i];
        if (startDay <= item.timestampMs && item.timestampMs <= endDay) {

            date = new Date(Number(item.timestampMs));
            latlngs.push(new google.maps.LatLng(item.latitudeE7 * 0.0000001, item.longitudeE7 * 0.0000001));

            //Generate speech bubbles
            var ins = '<div class="map-window">';
            ins += '<font size="2">'
            //ins += '<p class="map-window_name">' + date + '</p>';
            var flag = 0;
            var tw = 0;
            var itemNext = mapData[i + POINTS];

            //Reflect the Tweet content in the balloon
            for (var j = 0; j < tweetData.length; j++) {
                if (item.timestampMs <= (tweetData[j].created_at * 1000) && (tweetData[j].created_at * 1000) < itemNext.timestampMs) {
                    console.log(date);
                    console.log(tweetData[j].text);
                    ins += '<p class="map-window_name">' + tweetData[j].text + '</p>';
                    //Key to associative array"image"If there is, add an image
                    if (tweetData[j].image) {
                        ins += "<img src='" + tweetData[j].image + ":thumb'></br >";
                    }
                    tw = 1;
                }
            }
            ins += '</font>';
            ins += '</div>';

            //Generate balloons only for markers with Tweet
            if (tw == 1) {
                //Installation of markers
                var marker = new google.maps.Marker({
                    position: latlngs[markerNum],
                    map: map,
                    animation: google.maps.Animation.DROP,
                });

                var infoWindow = new google.maps.InfoWindow({
                    content: ins
                });

                infoWindowIndex[infoWindowNum] = i;
                infoWindowNum++;

                //Marker event settings
                add_event_to_marker(marker, infoWindow, i);
            }

            aveLat += (item.latitudeE7 * 0.0000001);
            aveLng += (item.longitudeE7 * 0.0000001)
            markerNum++;
        }

    }
    //Set the average of the coordinates to the center of the map
    aveLat /= markerNum;
    aveLng /= markerNum;
    map.setCenter(new google.maps.LatLng(aveLat, aveLng));

}

/**
 *Add an event to the marker
 * @param {object} marker     (required)Marker information
 * @param {object} infoWindow (required)Information on balloons
 * @param {number} index      (required)Map information index number
 */
function add_event_to_marker(marker, infoWindow, index) {
    var item = mapData[index];
    item['marker'] = marker;
    item['infoWindow'] = infoWindow;

    item['infoWindow'].open(map, item['marker']);

    //Display a balloon when the marker is clicked
    item['marker'].addListener('click', function (e) {
        infoWindows_hide();
        item['infoWindow'].open(map, item['marker']);
    });
}

/**
 *Hide the callout
 */
function infoWindows_hide() {
    for (var i = 0; i < infoWindowIndex.length; i++) {
        if (startDay <= mapData[infoWindowIndex[i]]['timestampMs'] && mapData[infoWindowIndex[i]]['timestampMs'] <= endDay)
            mapData[infoWindowIndex[i]]['infoWindow'].close();
    }
}

/**Display balloons in order*/
function infoWindows_open() {
    var j = 0;
    for (var i = 0; i < mapData.length; i++) {
        if (infoWindowIndex[j] == i) {
            mapData[i]['infoWindow'].open(map, mapData[i]['marker']);
            j++;
        }
    }
}


/**Generate a polyline*/
function generate_polyline() {
    //Draw a line
    lines = new google.maps.Polyline({
        path: latlngs,
        strokeColor: "#8a2be2",
        strokeOpacity: .7,
        strokeWeight: 5
    });
    lines.setMap(map);
}

map.html


<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8" />

    <title>Tweet map</title>

    <link rel="stylesheet" href="sample.css" />

</head>

<body>

    <div id="map"></div>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="./sample.js"></script>
    <script
        src="https://maps.googleapis.com/maps/api/js?key=<Prepared GCP key>&callback=api_ready"></script>

</body>

</html>

sample.css


#map {
    width: 1000px;
    height: 600px;
}

Although it is coded as Tara Tara, what I am doing is simple, I try to display tweets with a time close to the time at each point in the location history and the tweet time. Specifically, since the coordinates remained finely about every 3 minutes, the Tweet tweeted within the time with the location history and the next time (about 3 minutes later) is displayed.

In addition, the trajectory is also displayed using a Google Map method called polyline so that you can see the trajectory you moved.

3. Precautions

(1) Location information, Tweet content, and API key information are personal information, so never disclose them!

(2) When executing in a local environment, an error will occur when accessing a local file with Ajax with chrome. Run Chorme with sudo! [* Other *] Access local files with Ajax in Chrome

③ You can only go back to the date when you can get the location history and Tweet data! (Of course)

4. Referenced Web articles

It may be a reference or almost a copy. .. .. .. Excuse me. .. .. Thank you very much. (I referred to various sites, so please let me know if you say, "Oh, this code is a copy of the one I wrote?")

Use Google Timeline to record trips and outings

[Capture on the 10th day] Convert created_at of Twitter API to UNIX time and save it in DATETIME

Play with twitter API # 3 (Get search results)

-Displaying polylines Google Maps API V3 How to use JavaScript

Other

Since it is a type that I am satisfied with making, there may be some omissions in the explanation, but if it is difficult to understand, please ask. .. ..

Recommended Posts

Beginners of Google Maps API and Twitter API made "tweet map"
[Google Maps API] Map is not displayed and becomes blank [Rails]
[Rails] google maps api How to post and display including map information
Use twitter API (API account registration and tweet acquisition)
Display Google Maps API with Rails and pin display
Create a tweet heatmap with the Google Maps API
About the camera change event of Google Maps Android API
[Map display] Display a map from the address registered by the user using the Google Maps JavaScript API and Geocoding API!
Python beginners hit the unofficial API of Google Play Music to play music
[Ruby on Rails] Display and pinning of GoolgeMAP using Google API
Implement Twitter, Google, and email logins.
Introducing Google Map API with rails
Google API access token and refresh token
[Rails] Google Maps API Description when latitude and longitude cannot be saved
I made go language for api and minimum configuration of react for front
Get delay information on Twitter and tweet
I tried using Twitter api and Line api
Tweet using the Twitter API in Python
[Rails 6 / Google Map API] Post an address and set multiple markers on the map