Skip to content

Des graphiques à la Xkcd

Ou comment faire des graphiques dans le légendaire style de XKCD (une finesse du trait plus tranchante que Michel-Ange, des couleurs plus contrastées que Léonard de Vinci).

graphique à la xkcd

Les développeurs de Matplotlib l’ont fait et intégré à la bibliothèque. Globalement, il suffit d’initialiser le script python avec la fonction xkcd(). Cette fonction initialise des paramètres pour le rendu des graphiques.

with plt.xkcd():
    #le code pour produire le graphique

Installation

Dans Debian, le paquet de base de Matplotlib est python-matplotlib pour python2 et python3-matplotlib pour python3.

Pour que le graphique ait une police similaire à ceux de xkcd, la police Humor Sans doit être installée. Dans Debian, elle se trouve dans le paquet fonts-humor-sans.

Il est possible d’avoir encore une erreur signalant que la police n’est pas trouvée :

/usr/lib/python2.7/dist-packages/matplotlib/font_manager.py:1288: UserWarning: findfont: Font family [u'Humor-Sans'] not found. Falling back to Bitstream Vera Sans

En réalité, elle est bien accessible par matplotlib mais la bibliothèque a construit un cache des polices disponibles lors de la création d’un autre graphique par le passé. Ce cache n’est pas vidé après l’installation de la police. L’erreur survient car matplotlib regarde dans son cache et non les polices actuellement installées sur le système. Il suffit donc de supprimer ce cache (fontList.cache pour python2 ou fontList.py3k.cache pour python3) et d’exécuter à nouveau le script.


stephane@foehn:~$ ls .cache/matplotlib/
fontList.cache fontList.py3k.cache tex.cache
stephane@foehn:~$ rm .cache/matplotlib/fontList.cache #si script lancé avec python2

Et là, ça marche !:-)

Évitez tout de même de mettre des accents, la police ne dispose pas de ces caractères et un « ? » est affiché à la place.

Versions des logiciels utilisés, code source

paquet python-matplotlib : 1.5.1-1
paquet fonts-humor-sans : 1.0-1

Le code source qui a permis de produire le magnifique graphique inséré au début de l’article :

from matplotlib import pyplot as plt
import numpy as np

with plt.xkcd():
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    plt.xticks([])
    plt.yticks([])
    ax.set_ylim([-1, 2])

    x = np.linspace(0, 10)
    plt.plot(x, np.sin(x) + 0.3, '--')

    plt.xlabel('abscisses')
    plt.ylabel('ordonnees')
    plt.title("c'est le plus beau graphique du monde !")

    plt.savefig("/tmp/graph_xkcd.png")

Réflexions à propos de l’Open Gaming Licence

Wizard of the Coast est une entreprise éditrice de jeux. Les jeux les plus connus sont Magic: the gathering et Dongeons & Dragons, le premier jeu de rôle publié. La cinquième édition de Dongeons & Dragons vient d’être publiée. Une partie des règles, le System Reference Document 5.0 (SRD5), est publiée à part, sous une licence qu’ils ont créée en 2000 : « Open Gaming License » (OGL).

Le SRD5 contient les caractéristiques des classes de personnages et de monstres. Elle ne contient donc que des mécaniques de jeu, pas l’univers ou les personnages créés pour Dongeons & Dragons 5. Cela ressemble un peu à ce que font des éditeurs de jeu propriétaires qui libèrent le moteur mais pas les modèles et les textures inclus dans le jeu. Par exemple idSoftware le fait depuis longtemps avec les moteurs successifs de Doom, Quake, etc.

Comparaison avec le logiciel libre

Si on compare les libertés garanties par les licences considérées comme libres en informatique, il est nécessaire d’adapter les 4 libertés du logiciel libre à l’équivalent pour l’OGL :

  • la liberté d’exécuter le programme, quelque soit l’usage. Dans le cas de l’OGL, cela reviendrait à considérer que le contenu est utilisable pour n’importe quel jeu, univers, etc., quelque soit le support.
  • la liberté d’étudier le fonctionnement du programme, et de le modifier pour qu’il effectue n’importe quelle tâche informatique ; dans le cas de l’OGL, cela serait la liberté de modifier n’importe quelle règle.
  • la liberté de redistribuer des copies ; cette liberté ne nécessite pas d’aptatation pour s’appliquer à l’OGL.
  • la liberté de distribuer à n’importe qui des copies de versions modifiées ; cette liberté ne nécessite pas d’aptatation pour s’appliquer à l’OGL.

Pour les deux dernières libertés, l’accès au code source est une condition nécessaire. Dans le cas de SRD5, le texte est fourni au format pdf. L’origine du .pdf semble être un fichier .docx qu’il faudrait fournir (on peut l’assimiler au code source car c’est le fichier qui a permis de produire le fichier pdf). Je n’ai pas cherché s’il est disponible.

La licence commence par

Permission to copy, modify and distribute the files collectively known as the System Reference Document 5.0 (“SRD5”)

Ce qui sont les libertés requises de copie et de modification et de redistribution. Cependant, il faut lire la licence dans les détails pour savoir si qui est réellement permis et ce qui est interdit. Un epu plus loin, la définition g indique :

« Use », « Used » or « Using » means to use, Distribute, copy, edit, format, modify, translate and otherwise create Derivative Material of Open Game Content.

Le terme « use » recouvre l’équivalent des 3 premières libertés, la quatrième y est implicite.

Quelques détails

– Il est obligatoire de fournir la licence (clause 2 et 10) :

You must affix such a notice to any Open Game Content that you Use. (clause 2)

You MUST include a copy of this License with every copy of the Open Game Content You Distribute. (clause 10)

C’est une obligation classique que l’on retrouve dans les licences libres.

– Il est interdit de modifier la licence (clause 2) :

No terms may be added to or subtracted from this License except as described by the License itself. No other terms or conditions may be applied to any Open Game Content distributed using this License.

C’est une obligation classique que l’on retrouve dans les licences libres. En cas de modification, il faut donner un autre nom à la licence créée. Cela évite les confusions et il est possible de connaître les droits et obligations de la licence simplement en connaissant son nom.

– Si une nouvelle version de la licence est publiée, n’importe laquelle reste valide pour les utilisateurs.

You may use any authorized version of this License to copy, modify and distribute any Open Game Content originally distributed under any version of this License.

Cela provoque une incertitude quand aux choix futurs de Wizards of the Coast : l’évolution future des termes de la licence est inconnue et étant donné que n’importe quelle version de la licence peut être valide, les utilisateurs de l’OGL sont dans le flou. La General Public Licence propose de mettre la version pour laquelle le détenteur du droit d’auteur accepte (par exemple, version 2, version 2 et plus, version 3, version 3 et plus, etc.) que l’utilisateur utilise pour son usage, modification, etc. L’équivalent pour l’OGL ne serait pas « 1.0a et plus », car elle n’empêche pas non plus de prendre une plus ancienne.

– Le respect de l’ensemble des obligations de la licence est obligatoire (clause 3). C’est une obligation classique que l’on retrouve dans les licences libres. En cas de non respect, les droits octroyés par la licence s’arrêtent (clause 13).

– Il est possible de commercialiser une version modifiée ou non. L’interdiction de commercialisation rendrait la licence non-libre selon les critères du secteur informatique. Aucune clause de l’OGL n’interdit un usage commercial. La clause 11 interdit l’usage du nom des autres contributeurs pour la commercialisation, sauf autorisation expresse :

You may not market…using the name of any Contributor[…]

Cependant, on peut lire sur toutes les pages dans le pied de page du document :

Not for resale. Permission granted to print or photocopy this document for personal use only.

Cette mention ne me semble pas correcte avec la licence.

– L’OGL porte une attention particulière à la protection des éléments qui ne sont pas sous OGL. Les parties sous OGL doivent être clairement définis (clause 8). Il est interdit d’utiliser le nom des contributeurs sans leur autorisation expresse (clause 11). Il est interdit de faire référence aux noms protégés (clause 7), sauf autorisation expresse du détenteur des droits sur les noms. Il semble évident que Wizard of the Coast a voulu empêcher des concurrents potentiels de réutiliser les termes connus et l’univers de D&D pour éviter toute concurrence sur ce terrain.

Versions et exclusion de garantie

La version utilisée pour SRD5 vers la 1.0a.

Si jamais le SRD5 disparaît du site officiel, il reste téléchargeable à http://stephane.yaal.fr/licence_ogl_dd/SRD-OGL_V1.1.pdf. Le licence est placée sur les deux premières pages du document.

Je ne suis pas juriste, donc si vous voulez être plus rassuré, payez-en un pour qu’il lise le texte mieux que moi.

Bonnes fêtes en équation

J’ai pu voir récemment une image d’une équation se transformant en « merry x-mas ».

Trouvant l’idée amusante, je me suis essayé à l’exercice :
Équation bonnes fêtes

Bien que ce ne soit pas très difficile, le raisonnement est inverse à celui auquel on est habitué : il ne faut pas simplifier/factoriser/transformer une équation pour trouver la (les) solution(s) mais partir du résultat (le message que l’on veut obtenir) pour le rendre moins lisible au premier abord.

Techniques utilisées ou envisagées

– utiliser des produits plutôt que des sommes. En effet, l’insertion de signes + ou – sont problématiques pour la lecture.
– utiliser les puissances pour écrire un peu différemment et profiter des règles de calcul des puissances.
– utiliser un produit remarquable. J’ai essayé avec (n² + es²) mais je n’ai rien trouvé de probant avec la suite des transformations.
– utiliser des logarithmes ou exponentielles pour modifier l’équation. Pratique pour cacher le résultat final. Je n’ai pas utilisé cette astuce.
– utiliser une intégrale pour faire le « f ». L’inconvénient est qu’il faut indiquer les bornes de l’intégrale pour que l’expression soit correcte, ce qui va gêner la lecture.

Crédits

Merci à Gilles BM pour la relecture attentive de la résolution de l’équation.:-)
L’image au debut de l’article est une capture d’écran des équations écrites avec LaTex. Le code source LaTex et le fichier pdf sont téléchargeables dans les liens situés au début de cette phrase.

La version de pdflatex pour produire le pdf :
$ pdflatex --version
pdfTeX 3.14159265-2.6-1.40.16 (TeX Live 2015/Debian)
kpathsea version 6.2.1
Copyright 2015 Peter Breitenlohner (eTeX)/Han The Thanh (pdfTeX).
There is NO warranty. Redistribution of this software is
covered by the terms of both the pdfTeX copyright and
the Lesser GNU General Public License.
For more information about these matters, see the file
named COPYING and the pdfTeX source.
Primary author of pdfTeX: Peter Breitenlohner (eTeX)/Han The Thanh (pdfTeX).
Compiled with libpng 1.6.17; using libpng 1.6.17
Compiled with zlib 1.2.8; using zlib 1.2.8
Compiled with poppler version 0.38.0

hglib, la bibliothèque python pour s’interfacer avec Mercurial

Mercurial, un système de gestion de version décentralisé, propose hglib pour pouvoir agir sur un dépôt programmatiquement depuis Python.

Hglib est compatible avec python 2 et 3 donc, à moins de faire de l’archéologie logicielle (python 2.3 et encore plus vieux), il n’y a pas de raison de s’en priver.

L’installation est triviale puisque la bibliothèque est disponible à partir de pypi (donc utilisable dans un virtualenv) ou dans votre distribution préférée (paquet python-hglib ou python3-hglib avec Debian).

Créer un dépôt

>>> import hglib
>>> depot = hglib.init(dest="/tmp/geographie")
>>> print(depot)
<hglib.client.hgclient object at 0x7f9e75dc2250>

Le résultat est équivalent à la commande :

$ hg init /tmp/geographie

Le résultat est banalement prévisible :

$ ls -la /tmp/geographie/
total 268
drwxr-xr-x  3 alice    alice     4096 oct.  13 21:07 .
drwxrwxrwt 17 root     root    262144 oct.  13 21:08 ..
drwxr-xr-x  3 alice    alice     4096 oct.  13 21:07 .hg

Accéder au dépôt

Pour ouvrir le dépôt :

>>> import hglib
>>> depot = hglib.open("/tmp/geographie")
>>> print(depot)
<hglib.client.hgclient object at 0x7f2b230a8050>

Il est possible de voir et ajouter des branches :

>>> depot.branches()
[]  #pas de branche particulière
>>> depot.branch()
'default' #'default' est la branche que Mercurial crée par défaut
>>> depot.branch("dev") #création et passage sur la branche 'dev'
'dev'
>>> depot.branch()
'dev'
>>> depot.branches()
[]
>>> depot.commit("ajout de la branche dev")
(0, 'f1c9646830e4efc57830ddd588001917c3046e5d')
>>> depot.branches()
[('dev', 0, 'f1c9646830e4')] #la branche 'dev' est maintenant visible

depot.commit() retourne un couple (numéro de révision, identifiant du nœud).
depot.branches() retourne la liste des branches, chacune avec le triplet (nom de la branche, numéro de révision, identifiant du nœud).

Ajouter des fichiers

Supposons que nous ayons un fichier listant les villes de France nommé villes.tsv et que nous décidions de l’ajouter à notre dépôt :

>>> depot.add("/tmp/geographie/villes.tsv") #équivaut à hg add /tmp/geographie/villes.tsv
True
>>> depot.status() #équivaut à hg status
[('A', 'villes.tsv')]
>>> depot.commit("ajout des villes") #équivaut à hg commit -m"ajout des villes"
(1, '815765cc96bde95ff8ca02305f798e1effc31688')
>>> depot.status()
[]

depot.status() retourne une liste des changements. Chaque changement est représenté par un couple (lettre_code, fichier). lettre_code vaut les valeurs classiques :

  • M : fichier modifié
  • A : fichier ajouté
  • R : fichier supprimé
  • etc.

Modifier des fichiers

Malheureusement, une erreur s’était glissée dans le fichier villes.tsv… Après la correction mais avant le commit :

>>> depot.diff() #le diff brut de décoffrage
'diff -r 815765cc96bd villes.tsv\n--- a/villes.tsv\tTue Oct 13 21:49:41 2015 +0200\n+++ b/villes.tsv\tTue Oct 13 22:13:12 2015 +0200\n@@ -13492,7 +13492,7 @@\n giey-sur-aujon\tGiey-sur-Aujon\n giez\tGiez\n giffaumont-champaubert\tGiffaumont-Champaubert\n-png-sur-yvette\tPng-sur-Yvette\n+gif-sur-yvette\tGif-sur-Yvette\n gigean\tGigean\n gignac-34\tGignac\n gignac-46\tGignac\n'
>>> for ligne in depot.diff().split('\n'):) #équivaut à hg diff
...  print(ligne)
... 
diff -r 815765cc96bd villes.tsv
--- a/villes.tsv	Tue Oct 13 21:49:41 2015 +0200
+++ b/villes.tsv	Tue Oct 13 22:13:37 2015 +0200
@@ -13492,7 +13492,7 @@
 giey-sur-aujon	Giey-sur-Aujon
 giez	Giez
 giffaumont-champaubert	Giffaumont-Champaubert
-png-sur-yvette	Png-sur-Yvette
+gif-sur-yvette	Gif-sur-Yvette
 gigean	Gigean
 gignac-34	Gignac
 gignac-46	Gignac

Après le commit, le diff est aussi vide qu’on peut s’y attendre :

>>> depot.commit("correction gif-sur-yvette")
(2, 'a972c3bee591b2ec549420ef6fbe36e2cc433189')
>>> depot.diff()
''

depot.diff() accepte un nom de fichier ou une plage de révisions en paramètre pour limiter les résultats.

Voir l’historique

L’équivalent de hg log est aussi disponible :

>>> import pprint # c'est juste pour la lisibilité
>>> pprint.pprint(depot.log())
[('2',
  'a972c3bee591b2ec549420ef6fbe36e2cc433189',
  'tip',
  'dev',
  'Alice <alice@pays-des-merveilles.tld>',
  'correction gif-sur-yvette',
  datetime.datetime(2015, 10, 13, 22, 21, 53)),
 ('1',
  '815765cc96bde95ff8ca02305f798e1effc31688',
  '',
  'dev',
  'Alice <alice@pays-des-merveilles.tld>',
  'ajout des villes',
  datetime.datetime(2015, 10, 13, 21, 49, 41)),
 ('0',
  'f1c9646830e4efc57830ddd588001917c3046e5d',
  '',
  'dev',
  'Alice <alice@pays-des-merveilles.tld>',
  'ajout de la branche dev',
  datetime.datetime(2015, 10, 13, 21, 18, 34))]

C’est une liste de commits. Chaque commit est un n-uplet (numéro de la révision, identifiant du nœud, tip ou pas, branche, auteur, message, date).

Créer une archive

Vu l’avancée pour l’humanité réalisée, il est temps de faire une archive du projet :

>>> depot.archive("/tmp/archive") # équivaut à hg archive /tmp/archive

Le répertoire obtenu :

$ ls -la /tmp/archive/
total 1200
drwxr-xr-x  2 alice    alice     4096 oct.  13 22:41 .
drwxrwxrwt 18 root     root    262144 oct.  13 22:41 ..
-rw-r--r--  1 alice    alice      168 oct.  13 22:41 .hg_archival.txt
-rw-r--r--  1 alice    alice   948448 oct.  13 22:41 villes.tsv

Générique de fin

Ce n’était qu’un survol des possiblités de hglib. De nombreuses possibilités n’ont pas été abordées (ouvrir un dépôt distant, depot.pull(), depot.push(), la création de .tar.gz pour les archives, etc.). La plupart des méthodes prennent des paramètres facultatifs pour en modifier le comportement.

Les cascades de cet article ont été réalisées avec Python 2.7.10, Mercurial 3.4.2 et hglib 1.7-1. Vous pouvez les reproduire chez vous, même si vous n’êtes pas un professionnel.

Aucun terminal n’a été maltraité lors de la réalisation de cet article.

DebConf15 à Heidelberg

Je suis à la DebConf15 et j’ai des preuves :

club_mate

La photo a été prise dans l’auberge de jeunesse. Le Club-Mate, c’est un peu la baguette des Allemands, avec la bière et la porte de Brandebourg. (La porte est un peu plus difficile à boire.)

Le logo compatible Club-Mate :
Dc15going1