In [5]:
#http://docs.tweepy.org/en/latest/
#https://wafawaheedas.gitbooks.io/twitter-sentiment-analysis-visualization-tutorial/sentiment-analysis-using-textblob.html
#https://stackoverflow.com/questions/41058798/python-geopy-error-handling
#https://www.earthdatascience.org/courses/earth-analytics-python/using-apis-natural-language-processing-twitter/analyze-tweet-sentiments-in-python/

from geopy import geocoders
from geopy.exc import GeocoderTimedOut
import tweepy
from tweepy import OAuthHandler
from textblob import TextBlob
import json
import csv

#tweepy keys
CK = ''
CS = ''
AK = ''
AS = ''

#set up tokens
auth = tweepy.OAuthHandler(CK, CS)
auth.set_access_token(AK, AS)

#make our code wait in case it hits our rate limits
api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)

#search term (filters out retweets)
new_search = 'coronavirus -filter:retweets'

#create list to store tweets in
tweets = []

#search for tweets based on search term, language, and location, and append to the list
for tweet in tweepy.Cursor(api.search,
              q=new_search,
              lang='en',
              geocode='39.50,-98.35,2000mi').items(300):
    tweets.append(tweet)

#geocode the location of the tweets
def geo(location):
    g = geocoders.Nominatim(user_agent='emge', timeout=None)
    try:
        loc = g.geocode(location)
        return loc.latitude, loc.longitude
    except:
        return None

#write the tweet info to a csv
def WriteCSV(user, text, sentiment, lat, long):
    f = open('tran_emge_tweets.csv', 'a', encoding="utf-8")
    write = csv.writer(f)
    write.writerow([Author, Text, Sentiment, Lat, Long])
    f.close()

#defines variables for the tweet's author, text, sentiment, and location, and appends it to the csv
for tweet in tweets:
    Author = tweet.author.screen_name
    Text = TextBlob(tweet.text)
    Sentiment = Text.sentiment.polarity
    if tweet.user.location is not None:
        if geo(tweet.user.location) is not None:
            Lat,Long = geo(tweet.user.location)
            WriteCSV(Author, Text, Sentiment, Lat, Long)
    else:
        print('No location information')
Out[5]:
User Tweet Sentiment Lat Long
0 skirchy @jessbrammar @jane49578228 @high_fades @JuliaH... 0.00000 38.894893 -77.036553
1 Maku1316 SPRING BREAK CANCELED!? Miami Calls Coronaviru... 0.20000 36.701463 -118.755997
2 AspergersAreUs @astradisastra thank you for being the only pe... 0.00000 42.360253 -71.058291
3 rtw702 @messquire23 How could you possibly spend any ... -0.15625 22.736266 -81.815918
4 Divi9elyTay Oh heck! 😩😵😷\r\n\r\nFirst 2 cases of coronavir... 0.32500 32.329381 -83.113737
In [6]:
#print the results in a pandas table
import pandas

tweets = pandas.read_csv('tran_emge_tweets.csv', names=['User', 'Tweet', 'Sentiment', 'Lat', 'Long'])
tweets
Out[6]:
User Tweet Sentiment Lat Long
0 cullinwible @traderstewie Comparing the flu to the #corona... 0.000000 40.075738 -74.404162
1 Dizzedcom Coronavirus updates: Deaths pass 3,000, half o... -0.166667 40.712728 -74.006015
2 EntwistleF G7 finance ministers plan call on coronavirus ... 0.000000 50.000678 -86.000977
3 newsfilterio Cruise line stocks fall as coronavirus cases i... 0.000000 40.712728 -74.006015
4 lame_uhl don’t wash your hands because you’re afraid of... -0.250000 32.329381 -83.113737
5 EastIslipPatch Also: Rare snowy owl spotted / Coronavirus can... 0.050000 40.732082 -73.188330
6 eastvillagetwt NYC doctor has to 'plead' with health departme... 0.000000 40.729269 -73.987361
7 jamiaw Coronavirus forces MTA to give the subway a th... 0.000000 -1.291466 36.783078
8 GuardianAus The first economic modelling of coronavirus sc... -0.183333 -24.776109 134.755000
9 jobinindia Uber tells drivers to stay home if they have t... 0.000000 43.653963 -79.387207
10 RealTwitish @KitkatBunz "All pets of people in Hong Kong i... 0.000000 36.701463 -118.755997
11 realhumanrights #USA #COVID19 #Coronavirus cases confirmed / p... 0.313636 38.894893 -77.036553
12 DrJenniferCreed Pet dog in Hong Kong tests weak positive for c... -0.073864 40.079661 -89.433729
13 runderrickbean NHL looking at possiblity of playing in empty ... -0.075000 39.936836 -120.947176
14 JohnForberger I heard tomorrow is cancelled because of #coro... 0.000000 25.774266 -80.193659
15 podc Elizabeth Warren on Mike Pence leading the cor... -0.400000 40.712728 -74.006015
16 NYCLU We need to move quickly to fund and support a ... 0.236111 40.712728 -74.006015
17 HEKsROCKS101091 Dictatorships Are Making the Coronavirus Outbr... -0.400000 40.712728 -74.006015
18 AliEhsassi Travellers from Iran asked to self-isolate for... 0.000000 43.653963 -79.387207
19 skulIhong_ Coronavirus Could Spread in U.S. Because Peopl... 0.000000 40.712728 -74.006015
20 CityLifeLove Literally I watched all 3 hours of the today s... 0.500000 39.100105 -94.578142
21 michaelduffin Despite concerns about coronavirus, @sxsw will... 0.000000 38.894893 -77.036553
22 miranda_baddie Y’all have GOT to stop with this coronavirus b... 0.000000 32.080926 -81.091177
23 DJDARKKNYGHT Coronavirus my save my ass from taking this da... -0.600000 41.796241 -71.599237
24 MrsStewcifer Hey #KAG2020 watch this. It's all about your m... 0.000000 31.816038 -99.512099
25 FirstMainDesign Redmond, Washington, declares state of emergen... 0.000000 39.783730 -100.445882
26 GenieJeanJ @GovMikeHuckabee Why isn't Trump sucking the C... 0.000000 39.783730 -100.445882
27 bren2915 New York City doctor says he has to ‘plead to ... 0.136364 39.783730 -100.445882
28 API_VERACRUZ COVID-19 https://t.co/KJRiVCOqKO 0.000000 19.333333 -96.666667
29 TinaStitzer @realDonaldTrump The flu vaccine will NOT work... 0.000000 26.023220 -80.341239
... ... ... ... ... ...
261 Hephaestus7 Weekly Round up : March Madness - UK Human Rig... -0.100000 61.066692 -107.991707
262 deelotweets @ItsmeEddieC I didn't much care about coronavi... 0.200000 40.808886 -96.707775
263 boopstawista @eva_friederike The boys should be reading twe... 0.000000 40.712728 -74.006015
264 Pamela_Pikachu Covid19 Update... #Covid19 #CoronaVirus #CoVid... 0.000000 41.524492 -86.273340
265 retirednanny @GMA @DrJAshton I have Immune Deficiency Disea... 0.000000 28.851817 -81.710855
266 NEWZFOX https://t.co/HHGtKFSkD5 Coronavirus: Zimbabwe ... 0.200000 20.353622 100.081253
267 jerees Hey @CNNCenter, we’ve got @CNN covering the co... 0.000000 33.447336 -84.146862
268 MichaelShindler "Yeah, coronavirus is cool, but maybe the real... 0.275000 38.894893 -77.036553
269 svinnie_ i can't wait to see if i find out there's a co... 0.250000 10.750008 -75.000009
270 edodonnell8 @realDonaldTrump So many LIES .. Remember a co... 0.500000 34.021883 -118.285867
271 hacarter44 An Obama Holdover in an Obscure Government Arm... 0.000000 39.783730 -100.445882
272 The_News_DIVA New York Gov. Cuomo says community transmissio... 0.128788 41.208384 -73.890169
273 ShamonPR COVID-19 has shown workplace discrimination re... 0.000000 42.296486 -71.292557
274 alliejolley This coronavirus is seriously getting out of c... -0.333333 34.070958 -84.274733
275 Summerca Yet another liar regarding the seriousness of ... 0.000000 36.701463 -118.755997
276 TonyRenner @fairchild01 @thespybrief "Source familiar wit... 0.375000 38.652954 -90.241117
277 JeanneStumbaugh Friend pooh-poohed media coverage on the Coron... 0.000000 39.734838 -104.965327
278 kremlinkowboy The Center for Communicable Disease Dynamics e... -0.100000 39.783730 -100.445882
279 CaptDPC https://t.co/tWb7mGKsu2\r\nDo you want the fac... 0.000000 36.701463 -118.755997
280 DucVegso African countries are at severe risk if outbre... 0.050000 45.537258 -73.904332
281 margreis9 How to build public trust in the face of coron... 0.000000 39.906750 -76.700895
282 jennyncolor @realDonaldTrump Please address this crisis!! ... -1.000000 36.062584 -94.157433
283 alaskaneagle59 They say "you don't need a mask for the COVID ... -0.714286 64.445961 -149.680909
284 Rod_Boston Whatever ends up happening with coronavirus, i... 0.800000 42.360253 -71.058291
285 SgtTim911 This may indicate DHS needs to immediately tra... 0.107143 19.558404 -99.027741
286 RoBeck1963 @gtconway3d Hopefully no one at those rallies ... 0.000000 43.644764 -114.015407
287 TheLastO_G_ CORONAVIRUS just go away. 0.000000 27.756767 -81.463983
288 nations_2 @OneClassyLady7 @RepSwalwell By the way, here’... 0.000000 39.783730 -100.445882
289 Glorystar7777 Haitian Rhum plus pure organic black pepper mi... 0.015873 33.387058 -84.282978
290 RussellWayneEv1 @enriri Dr Li Wenliang, who was hailed a hero ... 0.100000 35.773008 -86.282008

291 rows × 5 columns

In [8]:
#sources in addition to documentation for libraries:
#https://stackoverflow.com/questions/56876620/unsure-how-to-use-colormap-with-folium-marker-plot
#https://www.kaggle.com/daveianhickey/how-to-folium-for-maps-heatmaps-time-data

import folium
import pandas
from folium import plugins
from folium import FeatureGroup, LayerControl
from folium.plugins import HeatMap
import branca
import branca.colormap as cm

#import csv
tweets = pandas.read_csv('tran_emge_tweets.csv', names=['User', 'Tweet', 'Sentiment', 'Lat', 'Long'])

#generate folium map
map = folium.Map(location=[39.50, -98.35],
              zoom_start=3,
              tiles='Stamen toner')

#colorscale points layer
points_layer = FeatureGroup(name = 'Tweet Points (Red = Negative Sentiment, Blue = Positive Sentiment)')

#set color scale
colormap = cm.LinearColormap(colors=['red','blue'], index=[-1,1],vmin=-1,vmax=1)

#define variables
lat = tweets.Lat
lon = tweets.Long
pow = tweets.Sentiment

#define symbolization
for loc, p in zip(zip(lat, lon), pow):
    folium.Circle(
        location=loc,
        radius=10,
        fill=True,
        color=colormap(p),
        fill_opacity=0.7
    ).add_to(points_layer)

#heatmap layer
heatmap_layer = FeatureGroup(name = 'Tweet Heatmap')
tweet_locations = tweets[['Lat', 'Long']].values
HeatMap(tweet_locations).add_to(heatmap_layer)

colormap.add_to(map)
points_layer.add_to(map)
heatmap_layer.add_to(map)
folium.LayerControl(collapsed=True).add_to(map)

map
Out[8]:
In [ ]: