étiquettes superposées

From: alain guerreau (guerreau@msh-paris.fr)
Date: Mon Nov 22 2004 - 11:22:23 MET

  • Next message: Stephane DRAY: "Re: étiquettes superposées"

    Le forum d'ADE4 s'anime autour de la question des « étiquettes » ; je m'en
    réjouis, car c'est une difficulté qui m'irrite depuis le jour où j'ai
    effectué mes premières analyses factorielles, en 1978 :-(( JP Benzécri
    avait évacué la question en faisant réaliser les graphiques à la plume par
    une « petite main ». A l'époque du FORTRAN (et de tout ce qui allait avec),
    les listings comportaient, sous les graphiques, des listes (souvent longues)
    de points superposés non imprimés, que l'on reportait donc au crayon, au
    prix d'un effort très désagréable (variante de la méthode Benzécri ). Tout
    le système graphique s'étant trouvé, depuis, bouleversé, on a pris
    l'habitude, soit de tout afficher (d'où des gribouillis illisibles), soit de
    n'afficher qu'une partie (une variante étant le principe des étiquettes
    blanches d'ADE4). C'est, tout compte fait, presque pire que la méthode
    Benzécri.

    Alors, pourquoi si peu de réflexions et d'efforts pour mettre au point une
    solution réaliste ? Depuis les travaux de Jacques Bertin (début dans les
    années 40, fin vers 1975), je n'ai vu apparaître, du moins en français,
    aucune réflexion vraiment méthodique sur la « statégie graphique » dans le
    domaine statistique. C'est pourtant un champ vaste et très prometteur. Mais
    qui suppose que l'on accepte l'idée qu'une exploration statistique n'est pas
    à 100% une affaire de maths et de théorèmes... Ici, pour faire très bref, je
    rappellerais seulement :
    1. qu'il est aisé de produire une infinité de graphiques inutiles et/ou mal
    conçus ;
    2. que l'on doit toujours partir de l'idée, défendue régulièrement sur le
    forum ADE4, mais nulle part dans les manuels, que, dans la grande majorité
    des cas, il existe une « pluralité de solutions optimales », ce qui implique
    qu'un grand nombre de discussions sont en réalité sans objet ;
    3. que l'on peut et doit généraliser cette proposition, tout simplement
    parce qu'un paquet de données plus ou moins structurées, même de petite
    taille, nécessite presque toujours un nombre important de graphiques (souven
    t plusieurs variantes du même, mais avec des paramètres différents).
    D'où l'idée, qui paraît trop simple pour être intéressante, que toute
    écriture de fonction graphique doit comporter par principe la possibilité de
    modifier un grand nombre de paramètres, de manière à permettre facilement la
    production très rapide d'une série de graphiques entre lesquels on
    déterminera empiriquement ceux sur lesquels on voit quelque chose et ceux
    sur lesquels on ne voit rien. Discuter à perte de vue sur « le bon paramètre
    de bandwidth », quel gaspillage !

    Les étiquettes. Il faut faire en sorte de fournir au chercheur devant son
    écran toutes les informations qui peuvent lui être utiles, et dont il peut
    avoir besoin. Et ce, sans qu'il lui soit nécessaire de manipuler des tas de
    fichiers dont il ignore d'ailleurs les noms... Mais il faut aussi tenir
    compte de deux contraintes, une matérielle et une théorique. 1. l'écran ou
    la feuille de papier n'ont qu'une taille limitée, 2. un bon graphique,
    lisible et interprétable, implique que le lecteur ne soit pas submergé. Je
    me limite ici aux analyses factorielles classiques.
    En simplifiant à outrance, il me semble que l'on se trouve devant un
    éventail de difficultés, en fonction du nombre d'étiquettes affichables.
    Grosso modo (à la louche) : jusqu'à 50, je veux voir toutes les étiquettes
    instantanément, sinon je juge la fonction mal foutue ; entre 50 et 250, ça
    se discute : on peut estimer qu'un affichage général de toutes les
    étiquettes va embrouiller au lieu de clarifier, mais l'inverse aussi, tout
    dépend de la signification desdites étiquettes ; il est plus que souhaitable
    qu'une possibilité d'affichage complet existe ; au-delà de 250, un affichage
    complet des étiquettes ne paraît plus guère se justifier, il faut faire
    ressortir des nuages de points significatifs ; on doit toutefois préserver
    la possibilité de faire apparaître ponctuellement l'étiquette de tel ou tel
    point (cas en général trop développé des outliers, mais qui existent tout de
    même).
    Techniquement (je parle en toute incompétence) : le dernier cas est sans
    doute le plus simple, sous R existe la fonction identify(), facile à mettre
    en oeuvre. On peut imposer quelques règles simples : pas d'étiquette de plus
    de 6 caractères, un affichage modeste (cex=.5, par exemple). Surtout, il est
    excessivement gênant que R ne dispose pas d'une fonction de « zoom » facile
    à mettre en oeuvre (si je me trompe et si elle existe, mille mercis de me le
    signaler). Je comprends encore bien moins pourquoi le paramètre din
    (par(din)) est en read.only, et pourquoi on ne peut pas définir sous R une
    image de taille quelconque dans laquelle on pourrait naviguer avec les
    barres de déroulement. (il existe apparemment une possibilité sous Linux,
    que je n'ai pas testée). Ce serait sans doute la meilleure solution pour la
    zone médiane (50-250). Il faudra bien un jour ou l'autre aller maniper dans
    les fonctions graphiques de base pour régler ce problème. Reste, en tout
    état de cause, la question des points strictement superposés, qui le
    resteront quelle que soit la taille de l'écran ou de la feuille. Je ne vois
    pas qu'on puisse faire l'économie d'un algorithme spécifiquement dédié à
    cette affaire. JP Benzécri aurait pu se fatiguer un peu plus. D'autant que,
    comme le montre l'expérience (eh oui, « le privilège de l'âge », comme je
    l'ai déjà lu dans ce forum...), les analyses factorielles les plus
    intéressantes sont le plus souvent celles qui font apparaître des « paquets
    de points », ou des zones de forte densité (type effet Gutmann). Et donc des
    étiquettes majoritairement superposées. Le gribouillis gâche tout le plaisir
    et empêche de comprendre ce qui se passe.

    C'est dans ces tristes conditions que j'ai imaginé la possibilité d'une
    fonction bancale et rudimentaire qui ferait disparaître cet inconvénient.
    L'idée est d'une navrante simplicité :
    1. calculer la distance de tous les points par rapport au centre du
    graphique.
    2. trier.
    3. en partant du centre, et en prenant les points dans l'ordre de cette
    liste, rechercher, pour chaque point et par rapport à lui, les points situés
    en deçà d'une distance x en largeur et y en hauteur.
    4. repousser vers l'extérieur (en fonction du cadrant dans lequel on se
    trouve), tous les points ainsi repérés, de telle sorte qu'ils se retrouvent
    au pire à ces distances critiques x et y.
    5. continuer jusqu'à extinction de la liste.

    en pratique, des choix s'imposent ; en particulier, doit-on ou non
    recalculer les distances au centre à chaque itération ? Sinon, repartir du
    centre autant de fois que nécessaire ? (ou un compromis ??). La fonction
    ci-dessous donne des résultats acceptables (c'est un avis) en dessous de 300
    points. Au-delà, elle peut encore marcher, en théorie, mais les temps de
    calcul s'allongent considérablement et finissent par tout bloquer. Surtout,
    inconvénient majeur (que certains jugeront probablement dirimant), cet
    algorithme déforme plus ou moins le nuage (dans des proportions très
    variables, en fonction de la quantité de points et de leur répartition).
    Pour mon usage personnel, je procède systématiquement en deux temps :
    1.affichage complet brut (donne la forme exacte du nuage et divers
    gribouillis), 2. affichage après passage de la fonction pousspouss(), nuage
    plus ou moins déformé, mais toutes les étiquettes lisibles. Avec les deux
    écrans ou les deux feuilles, je peux savoir immédiatement qui est qui, et
    où. Avec moins de 50 points et des paramètres graphiques modestes, la
    déformation est généralement à peine perceptible. Et quel confort !

    Bien entendu, les remarques, critiques, et je l'espère les propositions de
    modification / amélioration, me rendraient service. Cette fonction
    (typiquement du « programme spaghetti ») est publique (type de toutes les
    fonctions R). Il est à peu près certain qu'un algorithme meilleur doit
    exister.

    Alain Guerreau CNRS

    *******************************************

    "pousspouss" <-
    function (x,y,lab="",cex=0.8, vert=1){

    eps <- 0.00000009
    tabdep <- as.data.frame(cbind(x,y,lab))
    tabdep$x <- as.numeric(as.character(tabdep$x))
    tabdep$y <- as.numeric(as.character(tabdep$y))
    tabdep$lab <- as.character(tabdep$lab)
    for (i in 1:length(tabdep$x)){
    tabdep$ind[i] <- i
    tabdep$disct2[i] <- (tabdep$x[i]^2)+(tabdep$y[i]^2)}
    carlar <- max(nchar(tabdep$lab))
    r <- max((abs(max(tabdep$x)-min(tabdep$x))),
    ((abs(max(tabdep$y)-min(tabdep$y)))*1.3))

    recx <- r/(55/carlar/cex)
    recy <- r/(40/cex)

    ord <- order(tabdep$disct2)
    tabdep <- tabdep[ord,]
    tabpro <- tabdep
    i <- 1
    fin <- length(tabdep$x)

    while (i <= fin){
    px <- tabdep$x[i]
    py <- tabdep$y[i]
    ip <- NULL
    for (j in 1:length(tabdep$x)){
    if (i==j) next
    dx <- px - tabdep$x[j]
    dy <- py - tabdep$y[j]
    if (abs(dx) < (recx-eps) && abs(dy) < (recy-eps)){
    if ((abs(dy)*vert) <= abs(dx)){
    tabdep$y[j] <- (py + (recy*sign(tabdep$y[j])))}
    else {tabdep$x[j] <- (px + (recx*sign(tabdep$x[j])))}
    ip <- c(ip , j)
    }
    }
    i <- i+1
    if (length(ip)> 0 && min(ip)< i) {
    i <- min(ip)}
    }

    ord2 <- order(tabdep$ind)
    tabdep <- tabdep[ord2,]
    return(tabdep)
    }

    *******************************



    This archive was generated by hypermail 2b30 : Mon Nov 22 2004 - 11:25:13 MET