-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathTwitterMapper.java
194 lines (170 loc) · 7.19 KB
/
TwitterMapper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;
import twitter4j.*;
/**
* This class queries Twitter for tweets in a specific state that contain a specified keyword. It then associates a sentiment
* with that tweet. The sentiment for all tweets in a state is aggregated and averaged. The resulting average sentiments
* are then represented in a choropleth representing the sentiment of the tweets in each state.
*
* The data for the geographic center and area of each state was obtained from Wikipedia.
*
* The data is plotted using the DataMaps Javascript framework: <http://datamaps.github.io>. Specifically, the HTML file is
* based on the Choropleth with auto-calculated color example:
* <https://github.com/markmarkoh/datamaps/blob/master/README.md#choropleth-with-auto-calculated-color>.
*
* @author gcschmit (based on Twitter_Driver.java by Rita Galanos)
* @version 07jul2016
*/
public class TwitterMapper
{
private Twitter twitter;
private ArrayList<State> states;
private String keyword;
private static String HTML_TEMPLATE_FILENAME = "mapTemplate.html";
private static String STATE_DATA_FILENAME = "states.csv";
private static int MAX_TWEETS_PER_STATE = 100;
/**
* Standard main method for the program. Creates a TwitterMapper object for a given keyword, find tweets matching
* the keyword in each of the 50 US states, and then generates an HTML file visualizing the average sentiment
* of the tweets in each state.
*/
public static void main ( String[] args ) throws TwitterException, IOException
{
TwitterMapper twitterMapper = new TwitterMapper( "coding" );
}
/**
* Constructor for objects of class TwitterMapper.
*
* @param keyword the word that will be used to search for tweets
*/
public TwitterMapper(String keyword)
{
this.keyword = keyword;
// make an instance of Twitter - this is re-useable and thread safe.
twitter = new TwitterFactory().getInstance();
// load US state information
loadStateInformation( STATE_DATA_FILENAME );
}
/**
* Publishes the specified tweet from the account associated with this project.
*
* @param message the text of the tweet to publish
*/
public void tweetOut( String message ) throws TwitterException, IOException
{
twitter.updateStatus( message );
}
/**
* Searches Twitter for the specified number of tweets (MAX_TWEETS_PER_STATE) containing the keyword associated with this
* object in the specified state.
* The sentiment of each tweet will be calculated and the average sentiment of tweets associated with this state
* will be calculated and stored in the specified state object.
* Twitter allows queries to specify a geographic area in which to search for tweets. This area is specified as a
* geographic center and a radius. This doesn't exactly match to the boundary of a given state. Instead, the
* geographic center of the state is specified and the radius is specified to match a circle with the same
* area as the state.
*
* @param state search for tweets associated with this state
*
*/
public void findTweetsForState( State state) throws TwitterException
{
}
/**
* Searches Twitter for tweets containing the keyword associated with this object in each of the 50 US states.
* The sentiment of each tweet will be calculated and the average sentiment of tweets associated with each state
* will be calculated.
*
*/
public void findTweetsForAllStates() throws TwitterException, IOException
{
for( State state : this.states )
{
findTweetsForState( state );
}
}
/**
* Generates an HTML file that visualizes the resulting average sentiments for each states as a choropleth
* representing the sentiment of the tweets in each state.
*
* This method reads from a template HTML file and creates a new HTML file into which is inserted the sentiment values
* for each state. The name of the HTML file is the name of the keyword.html.
*
*/
public void mapSentimentForAllStates()
{
try
{
File htmlTemplateFile = new File( HTML_TEMPLATE_FILENAME );
Scanner in = new Scanner( htmlTemplateFile );
PrintWriter out = new PrintWriter( this.keyword + ".html" );
while( in.hasNextLine())
{
String line = in.nextLine();
if( line.contains( "### insert state data here ###" ))
{
// insert the sentiment values for each state according to the expected format
for( State state : this.states )
{
// for example: ["AL",0.75],
out.println( "[\"" + state.getAbbreviation() + "\"," + state.getSentiment() + "]," );
}
}
else if( line.contains( "### insert keyword here ###" ))
{
// insert the keyword which will be reflected in the header of the web page
out.println( this.keyword );
}
else
{
out.println( line );
}
}
out.close();
in.close();
}
catch( FileNotFoundException e )
{
System.out.println( "HTML Tempalte file: " + HTML_TEMPLATE_FILENAME + " not found." );
}
}
/**
* Creates a list of state objects based on data in the specified file.
*
* @param fileName search for tweets associated with this state
*
* @precondition the specified file must be a CSV file with four columns.
* The first contains the two-letter ANSI abbreviation for the state; the second, the longitude as a double;
* the third, the latitude as a double; the fourth, the area of the state in square miles.
*
*/
private void loadStateInformation( String fileName )
{
this.states = new ArrayList<State>();
try
{
File statesFile = new File( fileName );
Scanner in = new Scanner( statesFile );
in.useDelimiter( "[,\r\n]" );
while( in.hasNext())
{
String abbreviation = in.next();
Double longitude = in.nextDouble();
Double latitude = in.nextDouble();
Double area= in.nextDouble();
in.nextLine();
this.states.add( new State( abbreviation, new GeoLocation( longitude, latitude ), area ));
}
in.close();
}
catch( FileNotFoundException e )
{
System.out.println( "States file: " + fileName + " not found." );
}
}
}