Grafoscopio/src/Dataviz/TwitterProfileOverview.clas...

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.
]