293 lines
8.8 KiB
Smalltalk
293 lines
8.8 KiB
Smalltalk
"
|
|
I represent the overall activity of given twitter profile, in terms of
|
|
the kind of messages this profiles emits, being them: tweets, retweets
|
|
and replies.
|
|
"
|
|
Class {
|
|
#name : #TwitterProfileOverview,
|
|
#superclass : #RTBuilder,
|
|
#instVars : [
|
|
'avatar',
|
|
'messages',
|
|
'screenName',
|
|
'repliedTo',
|
|
'retweetedTo',
|
|
'interactionProfiles',
|
|
'database'
|
|
],
|
|
#category : #'Dataviz-Twitter'
|
|
}
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> avatar [
|
|
^ avatar form
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> avatar: aBitMap [
|
|
avatar := aBitMap
|
|
]
|
|
|
|
{ #category : #'data visualization' }
|
|
TwitterProfileOverview >> avatarWheel [
|
|
"I show the profile avatar surrounded by a wheel representing the proportion between tweets,
|
|
retweets and replies of such profile."
|
|
| b |
|
|
self messages ifEmpty: [^ self].
|
|
b := RTPieBuilder new.
|
|
b interaction popup.
|
|
b shape current
|
|
innerRadius: 150;
|
|
externalRadius: 165.
|
|
b objects: self messages splitByType values.
|
|
b slice: #size.
|
|
b normalizer distinctColor.
|
|
self avatar ifNotNil: [ b view canvas addShape: (TRBitmapShape new form: self avatar) ].
|
|
^ b view.
|
|
]
|
|
|
|
{ #category : #examples }
|
|
TwitterProfileOverview >> avatarWheelExample [
|
|
|
|
| o p |
|
|
o := self class new.
|
|
o screenName: 'ObjectProfile'.
|
|
o messages
|
|
tweetsSize: 200;
|
|
retweetsSize: 70;
|
|
repliesSize: 15.
|
|
p := TwitterProfile new scrapDataForProfile: o screenName.
|
|
o avatar: p avatar.
|
|
^ o avatarWheel
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> database [
|
|
| dataLocation |
|
|
(FileLocator documents / 'Grafoscopio') ensureCreateDirectory.
|
|
(FileLocator documents / 'Grafoscopio' / 'Projects') ensureCreateDirectory.
|
|
(FileLocator documents / 'Grafoscopio' / 'Projects' / 'DataSelfies') ensureCreateDirectory.
|
|
dataLocation := FileLocator documents / 'Grafoscopio' / 'Projects' / 'DataSelfies' / 'data-selfies.sqlite'.
|
|
database := UDBCSQLite3Connection on: dataLocation fullName.
|
|
^ database
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> database: anObject [
|
|
database := anObject
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
TwitterProfileOverview >> exportInteractionProfilesTo: aFileReference [
|
|
STON put: self interactionProfiles onStreamPretty: aFileReference writeStream
|
|
]
|
|
|
|
{ #category : #'data visualization' }
|
|
TwitterProfileOverview >> frequentTweetedWordsShown: aWorldAmount retweetedProfilesShown: rtProfilesAmount mentionedProfilesShown: mtProfilesAmount [
|
|
"I put all the avatar wheel with tags that come from predefined amounts"
|
|
| aColorPalette |
|
|
aColorPalette := { Color orange . Color black . Color red }.
|
|
^ self
|
|
frequentTweetedWordsShown: aWorldAmount
|
|
retweetedProfilesShown: rtProfilesAmount
|
|
mentionsProfilesShown: mtProfilesAmount
|
|
coloredWith: aColorPalette
|
|
]
|
|
|
|
{ #category : #'data visualization' }
|
|
TwitterProfileOverview >> frequentTweetedWordsShown: aWordsPercentage retweetedProfilesShown: rtProfilesPercentage mentionsProfilesShown: mtProfilesPercentage coloredWith: aColorPalette [
|
|
"I put all the avatar wheel with tags that come from predefined amounts"
|
|
| tweetsArc retweetArc mentionsArc tweetsWords retweetedProfiles mentionedProfiles visualWords arcs queries canvasTemp |
|
|
self messages ifNil: [ ^ self ].
|
|
tweetsArc := self avatarWheel canvas shapes at: 2.
|
|
retweetArc := self avatarWheel canvas shapes at: 1.
|
|
mentionsArc := self avatarWheel canvas shapes at: 3.
|
|
tweetsWords := self messages wordsByFrequencyInTweetsUpTo: aWordsPercentage.
|
|
retweetedProfiles := self messages retweetedProfilesByFrequencyUpTo: rtProfilesPercentage.
|
|
mentionedProfiles := self messages mentionedProfilesByFrequencyUpTo: mtProfilesPercentage.
|
|
arcs := { tweetsArc . retweetArc . mentionsArc }.
|
|
queries := { tweetsWords . mentionedProfiles . retweetedProfiles }.
|
|
canvasTemp := self avatarWheel canvas.
|
|
arcs doWithIndex: [ :arc :i |
|
|
visualWords := TPMessages new
|
|
visualWordsFrom: (queries at: i)
|
|
colored: (aColorPalette at: i).
|
|
arc color: (aColorPalette at: i).
|
|
arc
|
|
surroundedBy: visualWords
|
|
radialGap: 85
|
|
angularGap: 3
|
|
renderedIn: canvasTemp.
|
|
canvasTemp := canvasTemp
|
|
].
|
|
^ canvasTemp
|
|
]
|
|
|
|
{ #category : #'data scrapping' }
|
|
TwitterProfileOverview >> getAvatarForProfile: aTwitterProfile [
|
|
"I scrap the avatar image for aTwitterProfile and use it to fill my avatar form.
|
|
aTwitterProfile is the twitter's screen name, the string after the '@' character"
|
|
self avatar: (TwitterProfile new scrapAvatarForProfile: aTwitterProfile)
|
|
|
|
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
TwitterProfileOverview >> importIProfilesFromDB [
|
|
| query answer |
|
|
query := 'SELECT * FROM interaction_profiles;'.
|
|
answer := (self database open execute: query) rows collect: [ :each | each data ].
|
|
self database isOpen ifTrue: [ self database close ].
|
|
answer do: [ :each |
|
|
self interactionProfiles add:
|
|
(TwitterInteractionProfile new
|
|
screenName: (each at: 'screenName');
|
|
avatar: (FLMaterializer materializeFromByteArray: (each at: 'avatar'));
|
|
tweets: (each at: 'tweets');
|
|
retweets: (each at: 'retweets')
|
|
)
|
|
]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
TwitterProfileOverview >> importInteractionProfilesFrom: aFileReference [
|
|
STONReader fromSton: aFileReference contents
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
TwitterProfileOverview >> initialize [
|
|
super initialize.
|
|
avatar := RTBitmap new.
|
|
messagesStats := TPMessages new.
|
|
screenName := String new.
|
|
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> interactionProfiles [
|
|
^ interactionProfiles ifNil: [ interactionProfiles := OrderedCollection new ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> interactionProfiles: anObject [
|
|
interactionProfiles := anObject
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
TwitterProfileOverview >> materializeIProfilesFrom: aFileReference [
|
|
self interactionProfiles: (FLMaterializer materializationFromFileNamed: aFileReference fullName) root
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> messages [
|
|
^ messages ifNil: [ messages := TwitterMessages new ]
|
|
]
|
|
|
|
{ #category : #utility }
|
|
TwitterProfileOverview >> putAvatarsOnInteractionProfiles [
|
|
self interactionProfiles size isZero ifTrue: [ ^ self ].
|
|
self interactionProfiles do: [ :each |
|
|
each avatar: (TwitterProfile new scrapAvatarForProfile: each screenName)
|
|
]
|
|
]
|
|
|
|
{ #category : #utility }
|
|
TwitterProfileOverview >> putTweetsOnInteractionProfiles [
|
|
|
|
self sortedRetweetedTo keysAndValuesDo: [ :k :v | | ip|
|
|
ip := TwitterInteractionProfile new
|
|
screenName: k;
|
|
tweets: v.
|
|
self interactionProfiles add: ip
|
|
].
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> repliedTo [
|
|
^ repliedTo ifNil: [ repliedTo := OrderedCollection new ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> repliedTo: anObject [
|
|
repliedTo := anObject
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> retweetedTo [
|
|
^ retweetedTo ifNil: [ ^ retweetedTo := OrderedCollection new ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> retweetedTo: anObject [
|
|
reposted := anObject
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> screenName [
|
|
^ screenName
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
TwitterProfileOverview >> screenName: aString [
|
|
screenName := aString
|
|
]
|
|
|
|
{ #category : #'data queries' }
|
|
TwitterProfileOverview >> selectRepliesFrom: aJSONFile [
|
|
| allMessages |
|
|
allMessages := NeoJSONReader fromString: (aJSONFile readStream nextLine; upToEnd) contents.
|
|
self messages replies: (allMessages select: [ :each | each keys includes: 'in_reply_to_screen_name']).
|
|
^ self messages replies
|
|
]
|
|
|
|
{ #category : #'data queries' }
|
|
TwitterProfileOverview >> selectRetweetsFrom: aJSONFile [
|
|
| allMessages |
|
|
allMessages := NeoJSONReader fromString: (aJSONFile readStream nextLine; upToEnd) contents.
|
|
self messages retweets: (allMessages select: [ :each | each keys includes: 'retweeted_status']).
|
|
^ self messages retweets
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
TwitterProfileOverview >> serializeIProfilesTo: aFileReference [
|
|
FLSerializer newDefault serialize: self interactionProfiles toFileNamed: aFileReference fullName
|
|
]
|
|
|
|
{ #category : #'data queries' }
|
|
TwitterProfileOverview >> splitMessagesByTypeFrom: aJSONFile [
|
|
^ self messages splitByType
|
|
]
|
|
|
|
{ #category : #'data visualization' }
|
|
TwitterProfileOverview >> taggedWheelFull [
|
|
"I put all the avatar wheel with tags that come from predefined amounts"
|
|
self messages ifNil: [ ^self ].
|
|
self
|
|
frequentTweetedWordsShown: self messages tweetsSize
|
|
retweetedProfilesShown: self messages retweetsSize
|
|
mentionedProfilesShown: self messages repliesSize
|
|
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
TwitterProfileOverview >> updateDBWithInteractionProfiles [
|
|
|
|
|
|
| db |
|
|
db := UDBCSQLite3Connection on: self database.
|
|
db open.
|
|
db execute:
|
|
'CREATE TABLE IF NOT EXISTS interaction_profiles (
|
|
screenName text PRIMARY KEY,
|
|
avatar blob,
|
|
tweets integer,
|
|
retweets integer
|
|
);'.
|
|
self interactionProfiles do: [ :ip |
|
|
db
|
|
execute: 'INSERT INTO interaction_profiles values (?, ?, ?, ?);'
|
|
with: { ip screenName . ip avatar . ip tweets . ip retweets}
|
|
].
|
|
db close.
|
|
]
|