• fullscreen
  • ITicker.pde
  • IWordCloudLayoutEngine.pde
  • IWordColorService.pde
  • IWordFilter.pde
  • IWordReader.pde
  • ParagraphLayoutEngine.pde
  • Word.pde
  • WordCloud.pde
  • WordCloudGraphic.pde
  • WordGraphic.pde
  • obama_speech_word_cloud.pde
  • interface ITicker
    {
      void Tick();
    }
    
    class Ticker implements ITicker
    {
      IWordReader reader;
      PFont font;
      
      Ticker(IWordReader wReader, PFont wFont)
      {
        reader = wReader;
        font = wFont;
      }
      
      void Tick()
      {
        int pos = reader.CurrentPosition();
        int numOfWordsToShow = 7;
        String[] s = new String[numOfWordsToShow];
        s[0] = reader.ReadPosition( pos );
        for(int i= 0; i< numOfWordsToShow; i++)
        {
          if(pos > i)
          {
            s[i] = reader.ReadPosition( pos-i );
          }  
        }  
        
        //refresh ticker (paint ticker area all white)
        fill(255);
        noStroke();
        rect( 0, height-50 , width, 50 );
        
        //paint focused word
        fill(100);
        textFont( font, 32 );
        float[] wid = new float[numOfWordsToShow];
        for(int i=1; i < numOfWordsToShow; i++)
        {
          if(pos > i)
          {
          wid[i] = textWidth( s[i] );
          }
        }
        text( s[0], width/2-wid[0]/2, height-15);
        
        //paint previous words
        fill(200);
        float leftSideOfWord = width/2-wid[0]/2;
        for(int i=1; i< numOfWordsToShow; i++)
        {
          if(pos>i)
          {
            leftSideOfWord -= wid[i]+5;
            if( leftSideOfWord > -wid[i] )
            {
              text( s[i], leftSideOfWord, height-15);
            }
          }
        }
        
        
      }
    }
    
    interface IWordCloudLayoutEngine
    {
      HashMap Layout( WordCloud wCloud, PFont font );
    }
    
    interface IWordColorService
    {
      WordGraphic AddColorToWordGraphic(WordGraphic wg );
      WordCloudGraphic ColorCloud( WordCloudGraphic wcg );
    }
    
    class YesWeCanColors implements IWordColorService
    {
      ArrayList colorRed;
      
     YesWeCanColors()
      {
        GenerateColorsForWords();
      }
      
      //GenerateColorsForWords fills a hashmap with strings, and the color for that string
      void GenerateColorsForWords()
      {
        colorRed = new ArrayList(3);
        colorRed.add("yes");
        colorRed.add("we");
        colorRed.add("can");
      }
    
      WordGraphic AddColorToWordGraphic( WordGraphic wg )
      {
        if( colorRed.contains( wg.word.word ) )
        {
            wg.wordColor = color(231, 0, 10, 150);
        }else{
            wg.wordColor = color(41, 88, 156, 150);
        }
        
        return wg;
      }
      
      WordCloudGraphic ColorCloud( WordCloudGraphic wcg )
      {
        Iterator i = wcg.wordGraphics.values().iterator();
        while(i.hasNext())
        {
           WordGraphic wg = (WordGraphic) i.next();
           AddColorToWordGraphic( wg );
        }
        return wcg;
      }
    }
    
    interface IWordFilter
    {
      Boolean IsAWordToFilter( String s );
    }
    
    class WordFilter implements IWordFilter
    {
      ArrayList wordsToFilter;
      
      WordFilter()
      {
        GenerateWordsToFilter();
      }
      
      //GenerateWordsToFilter() fills a list of words which will not be displayed in the word cloud
      //these are typically common words which occur in english language and would dominate the cloud
      //but do not provide any useful meaning.  These are listed in a text file called wordsToFilter.txt
      void GenerateWordsToFilter()
      {
        wordsToFilter = new ArrayList();
        // Load file and chop it up
        String[] lines = loadStrings("wordsToFilter.txt");
        for( int i = 0; i < lines.length; i++)
        {
          wordsToFilter.add( lines[i] );
        }
      }
      
      //IsAWordToFilter determines whether a given word
      //should be filtered
      Boolean IsAWordToFilter(String s)
      {
        return !wordsToFilter.contains(s);
      }  
    }
    
    
    interface IWordReader
    {
      String ReadNext();
      int CurrentPosition();
      String ReadPosition(int position);
    }
    
    class WordReader implements IWordReader
    {
      
      String[] tokens;
      int counter;
      
      WordReader()
      {
        ParseText();
      }
      //ParseText reads in text from a file,
      //joins all the lines into one long line
      //and then splits the line into tokens
      void ParseText()
      {
        // Load file and chop it up
        String[] lines = loadStrings("Obama_Victory_Speech.txt");
        String allText = join(lines, " ");
        tokens = splitTokens(allText, " ,.?!:;[]-");
      }
      
      //GetNextWordToRead uses a counter to keep track of which word we are currently at
      //and gets the corresponding token from the array
      String ReadNext()
      {
        // Look at words one at a time
        String s = tokens[counter];
        s = s.toLowerCase();
        counter = (counter + 1) % tokens.length; //the modulus (%) ensures that once we finish reading the entire text, it starts again from the beginning
        return s;
      }
    
      int CurrentPosition()
      {
        return counter;
      }
      
      String ReadPosition( int position )
      {
        if( position < 0 ){
          position += tokens.length;
        }
        return tokens[position];
      }
      
    }
    
    class ParagraphLayoutEngine implements IWordCloudLayoutEngine
    {
      //this is used to control the number of words on the screen
      //if the screen becomes full, this threshold increases to reduce the number of words to be shown
      private int minWordCount;
      int lineHeight;
      float bottomMargin;
      float topMargin;
      int initialWordSize;
      int wordSize;
      int minWordSize;
          
      ParagraphLayoutEngine()
      {
        minWordCount = 1;
        lineHeight = 15;
        bottomMargin = 50;
        topMargin = 50;
        initialWordSize = 25;
        wordSize = initialWordSize;
        minWordSize = 18;
      }
      ParagraphLayoutEngine(int minimumWordCount, int heightOfLines, float marginAtTop, float marginAtBottom, int wordSizeAtStart, int minimumWordSize)
      {
        minWordCount = minimumWordCount;
        lineHeight = heightOfLines;
        topMargin = marginAtTop;
        bottomMargin = marginAtBottom;
        initialWordSize = wordSizeAtStart;
        wordSize = initialWordSize;
        minWordSize = minimumWordSize;
      }
      
      HashMap Layout(WordCloud wCloud, PFont font )
      {
        HashMap wordCloud = new HashMap();
        HashMap words = wCloud.words;
        
      
        // Make an iterator to look at all the things in the HashMap
        Iterator i = words.values().iterator();
      
        // x and y will be used to locate each word
        // set starting point of x and y
        float[] coord = new float[]{0, topMargin};
      
        while (i.hasNext()) {
          // Look at each word
          Word w = (Word) i.next();
          
          // Only display words that appear more than the minimum number of times
          if (w.count >= minWordCount) {
            
            int fsize = constrain(w.count, wordSize, 100);
    
            WordGraphic wg = new WordGraphic( w, f, fsize, coord[0], coord[1]);
            wordCloud.put( wg.word.word, wg );
      
            // x is changed to allow the drawing to move along the axis
            float wordWidth = wg.wordWidth();
            
            // If the word bleeds off the right of the window, need to move to new line
            if ( (coord[0] + wordWidth) > width) {
              coord = MoveToNewLine( wg, coord);
              
              // If y gets to the end, decrease the font size so more words can be displayed on the screen
              //if we are at the minimum word size, then increase the mininum Word Count so less words are displayed
              if (coord[1] > height-bottomMargin) {
                if( wordSize > minWordSize){
                  wordSize--;
                }else{
                  minWordCount++;
                  wordSize = initialWordSize;
                }
                break; 
              }
            }
            
            //now move to the end of the current word, which is the position for the next word
            coord[0] += wordWidth;
          }
         
          
        }
        return wordCloud;
      }
      
      public float[] MoveToNewLine(WordGraphic wg, float[] coord)
      {
        
        //move x and y to the start of the new line
              coord[0] = 0;
              coord[1] += lineHeight;
              //update the position of the word
              wg.x = coord[0];
              wg.y = coord[1];
              //wg.coord = coord;
              
              //return the updated positions
              return coord;
      }
    }
    
    class Word {
      
      int count;
      String word;
      
      Word(String s) {
        word = s;
        count = 1;
      }
      
      void CountOne() {
        count++;
      }
    
    }  
    
    public class WordCloud
    {
      HashMap words;
      IWordFilter wFilter;
      Word mostNumerous = new Word("");
      
      public WordCloud(IWordFilter wordFilter)
      {
        words = new HashMap();
        wFilter = wordFilter;
      }
      
      //AddWordToCloud accepts a string
      //it checks whether the string should be filtered
      //then it counts if the word has been counted before
      public void AddWord(String s)
      {
        if( wFilter.IsAWordToFilter(s) )
        {
          Word w;
          // Is the word in the HashMap
          if (words.containsKey(s)) {
            // Get the word object and increase the count
            // We access objects from a HashMap via its key, the String
            w = (Word) words.get(s);
            w.CountOne(); 
          } else {
            // Otherwise make a new word
            w = new Word(s);
            // And add to the HashMap
            // put() takes two arguments, "key" and "value"
            // The key for us is the String and the value is the Word object
            words.put(s, w);
          }
          
          if( w.count > mostNumerous.count)
          {
            mostNumerous = w;
          }
        }
      }
      
    }
    
    //This is responsible for ensuring a wordCloud can be painted to the screen
    class WordCloudGraphic
    {
      HashMap wordGraphics;
      IWordColorService wColorService;
      IWordCloudLayoutEngine wCloudLayout;
      
      WordCloudGraphic(IWordColorService wcService, IWordCloudLayoutEngine wcLayout )
      {
        wordGraphics = new HashMap();
        wColorService = wcService;
        wCloudLayout = wcLayout;
      }
      
      void CreateGraphic( WordCloud wCloud, PFont f )
      {
        wordGraphics = layoutEngine.Layout( wCloud, f );
        wColor.ColorCloud( this );
      }
      
      void PaintCloud()
      {
        // Make an iterator to look at all the things in the HashMap
        Iterator i = wordGraphics.values().iterator();
         while (i.hasNext()) {
           WordGraphic wg = (WordGraphic) i.next();
           DrawWordGraphic( wg );
         }
      }
    
      //DrawWordGraphic draws an individual word on the screen
      //at the x and y coordinates given in the WordGraphic properties
      void DrawWordGraphic( WordGraphic wg )
      {
        fill( wg.wordColor );
        textFont( wg.font, wg.fontSize );
        text( wg.word.word, wg.x, wg.y );
      }
    }
    
    class WordGraphic {
      
      Word word;
      PFont font;
      int fontSize;
      //float[] coord;
      float x;
      float y;
      color wordColor;
      
      //This allows words to be shown with differing sizes, fonts and colors
      WordGraphic(Word w, PFont f, int fSize, float xPos, float yPos) {
        word = w;
        font = f;
        fontSize = fSize;
       x = xPos;
       y = yPos;
       
       //coord = new float[]{x, y};
      }
      
      float wordWidth()
      {
        textFont(font, fontSize);
        return textWidth(word.word + " ");
      }
    } 
    
    /**
     * Obama Speech Word Cloud by Iain Sproat. 
     * 
     * This reads Obama's Victory speech
     * one word at a time, and generates a continually adjusting word cloud.
     *
     * Based on the Processing HashMap example
     * by Daniel Shiffman.
     */
    
    //HashMap words;
    
    IWordCloudLayoutEngine layoutEngine;
    IWordReader reader;
    IWordFilter wordFilter;
    IWordColorService wColor;
    WordCloud wCloud;
    WordCloudGraphic wcGraphic;
    
    ITicker ticker;
    
    PFont f;
    
    void setup() {
      //set the size of the screen
      size(640, 480);
      
      //setup the font we wish to use
      f = createFont("Georgia", 36, true);
      
      //initialize the services we wish to use
      reader = new WordReader();
      wordFilter = new WordFilter();
      wCloud = new WordCloud( wordFilter );
      wColor = new YesWeCanColors();
      layoutEngine = new ParagraphLayoutEngine();
      wcGraphic = new WordCloudGraphic( wColor, layoutEngine );
      ticker = new Ticker( reader, f );
      
      //set how fast the text is read onto the screen
      frameRate(6);
    }
    
    void draw() {
      background(255);
      
      String s = reader.ReadNext();
    
      ticker.Tick();
      
      wCloud.AddWord( s );
      
      //now we can create the image to be displayed for the current word cloud
      wcGraphic.CreateGraphic( wCloud, f );
    
      //display the word cloud on the screen
      wcGraphic.PaintCloud( );
    }
    
    
    
    
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    This sketch is saved as a draft and it is not published on the homepage and browse page.

    license

    advertisement

    Iain Sproat

    Obama Victory Speech Word Cloud

    Add to Faves Me Likey@! 5
    You must login/register to add this sketch to your favorites.

    Based on the Processing HashMap example by Daniel Shiffman, this reads in Obama's Victory speech one word at a time and generates a continually altering word cloud.

    wav, wish you could tie it up to his speech audio file, so word start showing up while he is speaking to them.
    very cool, thanks for sharing
    Iain Sproat
    21 Jan 2009
    This reads in his entire speech in a couple of minutes (and continually loops through it, exaggerating the font size of common words). It condenses the speech down from 20 minutes or so.
    I tried a text ticker, but it went to fast to be readable. A wav file with the speech at that rate would make him sound like a chipmunk!
    We could of course slow the rate of reading down, but it would lose the focus on the graphics - however you are more than welcome to try it.
    I tried it with the inaugural address, but he only said the word 'yes' once, so the red highlighting doesn't work so well graphically.
    Myer Nore
    24 Jan 2009
    Nice. I agree with Sinan - what makes Obama special is his voice. Does anyone have any pointers on how to programmatically identify the time locations of the words in an audio file if you have the transcript of the audio file? It's not exactly speech recognition...
    Iain Sproat
    13 Feb 2009
    I have updated the program. It now goes slower, and displays a word ticker. The layout of the words is also a bit better, being readable from the beginning.

    Features for the next version: If someone has a wav file, and an array of times which words are spoken then there is a possibility we can sync the word cloud to the speech.

    Codewise, in this version I have refactored to interfaces and have tried to seperate the counting of words, from the layout of the word cloud, and from the display of the word cloud and placed them in different classes.
    You need to login/register to comment.