Maak een woordenwolk generator.

Inleiding

Een woordenwolk kan gebruikt worden om een (lange) tekst in een beperkt aantal steekwoorden samen te ballen. Een woordenwolk bestaat uit een aantal woorden van verschillende grootte. De maat van de letters in een woord is meestal een aanduiding voor het belang van dat woord in de tekst. Op tagcrowd.com kan je zelf woordenwolken maken van een tekst. In deze opdracht maken we een vergelijkbare site, maar met andere mogelijkheden voor de gebruiker.

We maken de site in een aantal stappen waarbij in elke stap een bepaald aspect van programmeren in PHP aan de orde komt.

Stappenplan

  1. Stap Analyse Ga naar tagcrowd.com en experimenteer met alle mogelijkheden.

    Lees het Wikipedia artikel over tagclouds op http://en.wikipedia.org/wiki/Tagcloud.

    Opdracht

    1. In het Wikipedia artikel worden allerlei soorten tagclouds behandeld. Hoe worden de tagclouds in dat artikel genoemd die gemaakt worden op tagcrowd.com?
    2. Bekijk de prachtige tagcloud op deze pagina. Dat is een woordenwolk van deze pagina. Toch staan er vreemde woorden (of misschien beter gezegd "tokens") op. Waar komen die vandaan? Wat is hier mis gegaan? Leg je antwoord uit, en geef voorbeelden van tokens die niet in de wolk thuishoren.

  2. Stap HTML formulier en PHP antwoord Om een website te maken waar een gebruiker iets kan doen is er interactie nodig. Die interactie programmeren we met behulp van HTML formulieren.

    Techniek De volgende literatuur behandelt deze stof.

    Specifiek over het uploaden van files gaat dit stuk in de php.net tutorial. Hier leer je hoe je een file lokaal kan opslaan. De tekst uit een file opslaan als 1 string gaat heel eenvoudig met de file_get_contents() functie.

    Opdracht

    1. Maak een invoerscherm voor jouw woordenwolk site. Maak een formulier waarmee de gebruiker
      1. een stuk tekst kan intypen of plakken, en
      2. een (tekst) file kan uploaden.
    2. We willen ook dat de gebruiker een antwoord krijgt, en weet dat het opgestuurde goed is aangekomen. Schrijf een PHP script dat reageert als de gebruiker op submit heeft gedrukt en dan als antwoord het volgende laat zien:
      • (mits dit gebeurt is natuurlijk) de naam van de opgestuurde file, en
      • de opgestuurde tekst geplaatst in een apart blok op de webpagina met een gele achtergrond.

  3. Stap Van een tekst naar een rijtje woorden. Stel je tekst is via een het invoerveld ingevoerd en opgeslagen in de variabele $InvoerTekst. Nu willen we de losse woorden uit die tekst halen. Dit proces wordt tokenization genoemd: een tekst opsplitsen in tokens. In de meeste Westerse landen wordt de spatie gebruikt op woorden te scheiden. Dus als we de tekst splisen op spaties zijn we waarschijnlijk al een mooi eind op weg.

    Techniek Het Wikipedia artikel over taal analyse bevat een sectie over tokenization.
    We hebben de notie van een rijtje (een array) nodig om alle woorden in de tekst in de volgorde waarin ze in die tekst staan op te slaan.

    $InvoerTekst = "Hello World.";
    $woorderijtje = array("Hello", 
                          "World.");
    
    (NB. Waarom zit die punt nou nog aan het laatste token geplakt?)

    We hebben een functie nodig waarin we een string stoppen en een patroon wat dient als scheider en die dan een array met de tokens in die string gescheiden door die scheider teruggeeft. PHP heeft zo'n functie: preg-split(). Een simpelere functie waarin je alleen scheiders als strings kunt opgeven is explode().

    Literatuur

    Opdracht

    1. Splits je tekst op spaties met explode() en/of preg-split(). Begin met een zin bestaande uit zo'n 10 woorden. Dit is een mooie oefen zin:
      $str = "Mary Had A Little Lamb and She LOVED It So. SO! Lets see what
                happened to mary!";
      
    2. Oefen met een aantal array functies. Maak een PHP script waarin je steeds in een h2 tag de opdracht zet, en meteen daaronder jouw uitvoer programmeert, met een groene achtergrond.
      1. Print dat array uit.
      2. Sorteer het array en print het uit.
      3. Gebruik de PHP commandos foreach en echo om elk woord uit het array op een nieuwe regel uit te printen, zonder kommas.
      4. Print de woorden in omgekeerde volgorde uit.
      5. Print de woorden in willekeurige volgorde uit.
      6. Vertel hoeveel woorden er in de zin zitten.
      7. Print elk woord slechts 1 keer uit. Dus dubbelen mogen niet in je print zitten. Hoeveel unieke woorden zitten er in je invoerstring?
      8. Neem nu een wat langere tekst als invoer en tel weer de woorden. Plak die tekst ook in Word en tel daar ook de woorden. Is er een verschil? Kan je dat verklaren? Experimenteer net zo lang tot je een verschil krijgt.
      9. Er zitten vast ook allerlei leestekens in je lijst of aan woorden geplakt. Kan je dat verklaren?
      10. Is er een verschil tussen deze teksten? Zou je dezelfde lijst woorden eruit willen hebben, of juist niet? Motiveer je antwoord en kijk wat er in jouw programma gebeurt.
                 * Hello             World.
                 * Hello World.
                 * Hello
                   World.
                 * Hello World .
        
      11. Laat de gebruiker een getal n opgeven, en print alleen het n-de woord uit. Zorg dat er iets intelligents gebeurt als n te hoog wordt gekozen.
      12. Laat de gebruiker twee getallen n,m geven waarbij m groter dan n. Laat nu alle woorden vanaf het n-de en tot en met het m-de woord zien. Test eerst of inderdaad n kleiner dan m, en zo nee geef een foutmelding.

  4. Stap Op jacht naar patronen In de vorige opdracht zagen we dat tokenization op spatie alleen niet voldoende is. We zullen een meer ingewikkeld patroon moeten schrijven. Het efficient opschrijven en opzoeken van patronen gaat heel goed met zogenaamde reguliere expressies.

    Techniek Reguliere expressies

    Opdracht

    1. Wat betekent de reguliere expressie \W? Geef een beschrijving in woorden, en geef een preciese formele definitie in termen van een andere reguliere expressie. (Dat kan je als volgt doen: Stel je moet een definitie van a+ geven zonder + te gebruiken. Dan kan je zeggen dat a+ = aa*. Andersom kan ook a* = (a+)?.
    2. Maak een reguliere expressie die beter split dan alleen spatie. Een Google search op 'tokenization' of 'tokenize text regular expression' kan je goed helpen. Wikipedia ook trouwens.
    3. Splits je tekst opnieuw, maar nu met deze reguliere expressie. Beschrijf de verschillen die je ziet in de verschillende deelopdrachten van de vorige Stap.

  5. Stap Woordjes tellen en een histogram maken Eindelijk gaan we woordjes tellen en kunnen we dus beginnen met het maken van een woordenwolk. Het eerste idee is dat hoe vaker een woord voorkomt, hoe belangrijker het is, en dus hoe groter we het maken in onze wolk.

    Een hele handige en veel gebruikte data-structuur is de dictionary, ook wel associative array of hash array genoemd. Een dictionary, of kortweg dict, is een verzameling van sleutel-waarde paren. Dicts zijn voor van alles te gebruiken, maar ze danken hun naam aan het gebruik dat wij van ze gaan maken: opslaan hoe vaak een woord in een tekst voorkomt. Het idee is dat elk woord in een tekst een sleutel wordt met als waarde hoe vaak dat woord in de tekst voorkomt.

    Voorbeeld In onderstaand voorbeeld is de eerste variable een tekst-string, de tweede een lijst (gewoon array), en de derde een dict (associatief array).

    $tekst = "Wie ben ik? Ik ben ik!";
    $woordenlijst = array("Wie", "ben", "ik", "?", "Ik", "ben", "ik", "!");
    $histogram = array("Wie => 1,
                       "ben" => 2,
                       "ik" => 2,
                       "?" => 1,
                       "Ik" => 1,
                       "!" => 1);
    

    Opdracht

    1. Maak een dict zoals boven voor jouw lijst met woorden. Hint: gebruik foreach.
    2. Print die eerst uit als array, en daarna mooi met foreach en echo.
    3. Loop nu door het array en print die mooi uit als een HTML tabel, als volgt:
      Woord Aantal
      Wie 1
      ben 2
    4. Doe hetzelfde als in de vorige vraag maar orden de woorden nu op "populariteit", met het meest voorkomende woord eerst. Als meerdere woorden even vaak voorkomen orden je die alfabetisch.
    5. Loop weer door de array en print het nu uit als een comma separated value (csv) file, met ";" als scheider. Dus zo
      "Wie";1
      "ben";2
      "ik";2
      ...
      
      Zo'n file kan je inladen in Excel met het commando import. Doe dat en maak er in Excel een mooi histogram van. Maak nog een histogram maar nu met de ordening uit de vorige vraag.
    6. Google kan je ook helpen om mooie plaatjes te maken. Zoek uit hoe je een histogram maakt met Google charts, en maak zo'n histogram.
    7. Maak nu je eerste woordenwolk door alle woorden 1-voor-1 binnen een center HTML tag af te drukken. Zet om ieder woord een span tag en plaats binnen die span tag (CSS) style informatie over de font-size. Die font-size laat je natuurlijk bepalen door het aantal keer dat een woord voorkwam. Voor de leesbaarheid zal je de fontsize waarschijnlijk een functie moeten laten zijn van de waarde van een woord. Hint: kijk eens hoe andere sites dit doen. Dit kan heel makkelijk op http://www.tag-cloud.de/. Onderaan geven ze gewoon de HTML code van hun woordenwolk. Als ze dat niet doen, kan je natuurlijk altijd met view page source in je browser de HTML code van een webpagina bekijken.
    8. Print die wolk nu ook eens alfabetisch geordend uit. Daarvoor haal je de sleutels uit de dict met de keys() methode. Dat levert je een lijst met alle sleutels op. Orden die alfabetisch. Loop nu met foreach door die gesorteerde lijst en druk voor elke sleutel (= woord) dat woord af.
    9. Experimenteer met kleuren.
    10. Orden nu eens de woorden in je woordenwolk op lengte van het woord.
    11. Maak ook een random ordening.

  6. Stap Keuzes door de gebruiker. Voor de ene tekst wil je de instellingen zus hebben en voor de andere zo. Je wilt de gebruiker dus wat mogelijkheden geven om de gemaakte woordenwolk te controleren.

    Opdracht Maak een formulier waarmee je de volgende dingen kan instellen:

    1. Het maximaal aantal woorden in de wolk.
    2. Het minimale aantal keer dat een woord voorkomt in de tekst voordat het in de wolk komt.
    3. Het lettertype waarin de woorden staan.
    4. De kleur waarin de woorden staan, de achtergrond kleur.
    5. Verschillende volgordes van de woorden

  7. Stap Visueel aantrekkelijk maken. Bestudeer de woordenwolken gemaakt op wordle.net. Wow, dat is nog eens andere koek dan onze woordewolkjes.

    Opdracht Voeg toeters en bellen toe aan je woordenwolk applicatie. Het leukste is als de gebruiker zelf dingen in kan stellen. Ook is het gebruik van random dingen natuurlijk leuk. Een interresant iets is het varieren van de functie die aantallen afbeeldt op lettergroottes.

  8. Stap Linguistische verfijning Experimenteer met verschillende teksten met je woordenwolken. Je zal zien dat ze er nog niet zo goed uitzien als woordewolken die je gewend bent. Er vallen je vast de volgende dingen op:

    Opdracht

    1. Breidt het HTML-formulier uit een eerdere opdracht voor elke van de komende verbeteringen uit met een knop waarmee je ze aan en uit kan zetten, zodat je in stapjes kan laten zien hoeveel beter je woordenwolk applicatie geworden is.
    2. Haal leestekens weg met preg\_replace().
    3. Vervang in alle woorden hoofdletters door kleine letters. Maak nu een nieuwe woordenwolk. Voor deze taak zal PHP toch wel een functie op strings hebben?
    4. Google op "Nederlands stopwoordenlijst". Vind een lijst die je betrouwbaar acht. Download hem. Maak er een array van en schrijf een php programmatje dat alle woorden in jouw lijst verwijdert die ook in de stopwoorden lijst staan. Kijk eens goed rond in de lijst met array-functies. Dit is zo'n gebruikelijke operatie, zou daar niet al een PHP functie voor bestaan.....
    5. Bekijk de pagina over stemming in Wikipedia. Dit is een brute manier om verschillende woorden die komen van dezelfde stam terug te brengen tot 1 woord. Op die manier kunnen we natuurlijk mooi dat probleem met Nederland van boven oplossen.
      • (1) Verzin een aantal voor de hand liggende regels om te stemmen.
      • (2) Verzin voor elke regel een tegenvoorbeeld. (Bijvoorbeeld: ouders en ouderen stemmen allebei naar ouder, maar ze kunnen heel wat anders betekenen. Voor een mooi voorbeeld van Wilders, naar wilder, naar wild, zie deze blogpost.
      • (3) Implementeer je regels, en zorg dat je goed de waardes bij elkaar optelt. Let op, je moet de regels wellicht een heleboel keer toepassen! Hoe doe je dat? (Recursie! (Pas ze net zo lang toe tot er niks meer veranderd.).
      • (4) Bij stemming kan het zijn dat je gekke woorden terugkrijgt die geen Nederlands meer zijn. Dat wil je niet! Kies daarom voor elke groep van woorden die op elkaar gestemd worden 1 woord uit dat je gebruikt om te laten zien. Op basis waarvan kies je die? Argumenteer dat dit een goede keuze is. Implementeer het.
    6. Lees dit Wikipedia artikel over Automatisch zins ontleden (of part-of-speech tagging). Leg uit wat je hiermee kan in je woordenwolk applicatie.