2013-04-19 5 views
7

Nella pagina iniziale di matplotlib, c'è un collegamento a un tutorial di Nicolas Rougier. Nella sezione del tutorial dal titolo "Diavolo è nei dettagli", lo script:Specifica argomento del dizionario con dict() o argomenti contrasti in set_bbox

http://www.loria.fr/~rougier/teaching/matplotlib/scripts/exercice_10.py

produce la figura visualizzato nella pagina web. Linea 48 dello script è:

label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65)) 

Se sostituiamo questa linea da:

label.set_bbox({"facecolor": "white", "edgecolor": "None","alpha":0.65}) 

allora la richiesta edgecolor non viene presa in considerazione. Avrei pensato che le due affermazioni sopra erano equivalenti. Ho chiesto all'autore del tutorial, Nicolas Rougier, su questo e anche lui è sorpreso. È un bug di Matplotlib?

+0

Questo è davvero strano ... In realtà posso riprodurre questo ... – mgilson

+0

Il diavolo è davvero nei dettagli ... – BioGeek

+0

Ho il forte sospetto che questo sia correlato al 'alfa'. La gestione dei colori rgb vs rgba è delicata. Quale versione di mpl stai usando? – tacaswell

risposta

4

Si può facilmente determinare se i due dicts sono equivalenti:

dict(facecolor='white', edgecolor='None', alpha=0.65) == \ 
    {"facecolor": "white", "edgecolor": "None", "alpha":0.65} 

Questo è True.

Tuttavia, se si digita questi letterali in un interprete Python, il dizionario risultante repr s ha i valori in ordini diversi.

{'alpha': 0.65000000000000002, 'facecolor': 'white', 'edgecolor': 'None'} 
{'edgecolor': 'None', 'facecolor': 'white', 'alpha': 0.65000000000000002} 

Questo può variare in base alla versione di Python si usa, e credo che nelle versioni più recenti di Python varia da corsa per l'esecuzione dell'interprete; il seeding di hash è randomizzato per evitare che i dizionari vengano costruiti con prestazioni malevole. L'output sopra è da Python 2.6.6 (Win32).

Python dict s non ordinate, con cui intendiamo che non è possibile fare affidamento sull'ordine. Tuttavia, durante l'iterazione su un dizionario, gli elementi devono essere resi disponibili nell'ordine dell'ordine. Questo ordine è influenzato dall'ordine in cui gli articoli sono inseriti e, sebbene non sia ovvio, sono inseriti in due ordini diversi in questi due dizionari: il costruttore dict() ottiene un dizionario di parole chiave, che poi inserisce nel costruito dict, quindi gli elementi del primo dict vengono inseriti due volte! Per prima cosa nell'ordine in cui le specifichi, quindi in qualsiasi ordine finiscano nel dizionario costruito in quel passo.

Ipotesi:. C'è qualcosa in matplotlib (o la versione di Python che si sta utilizzando) che si prende cura quale ordine gli elementi del dizionario escono in Infatti, dal momento che il secondo ha prima la sua chiave edgecolor, forse è saltare la prima valore, o forse uno dei valori successivi ha un effetto collaterale che lo induce a sovrascrivere edgecolor (ad esempio, forse facecolor imposta anche edgecolor per assicurarsi che non vi siano spazi tra i volti). Questo potrebbe ragionevolmente essere definito un bug poiché il comportamento può variare in base all'ordine in cui le parole chiave vengono fuori dal dizionario.

+1

Questa è la conclusione a cui sono giunto anche io . My My, matplotlib si basa sull'ordine di dict. È inaspettato. Ricevo lo stesso tuo ordine sia per il costruttore di dict che per il letterale usando python2.7.3 su OS-X. Non sono sicuro quando attivano la casualizzazione dell'hash di default ... – mgilson

+0

Facendo qualche ricerca in più, sembra che la randomizzazione dell'hash fosse abilitata per impostazione predefinita in Python 3.3. – kindall

+0

Sembra che artist.update iterizzi sul dizionario e chiama le funzioni nell'ordine in cui gli elementi vengono recuperati, vedere https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/artist.py#L667. Il problema deve quindi trovarsi nella combinazione di 'set_edgecolor',' set_facecolor' e 'set_alpha'. –

0

Se si sostituisce la linea con:

label.set_bbox({"facecolor": "white", "alpha":0.65, "edgecolor": "None",}) 

funziona correttamente.

Penso che questo sia un bug in set_alpha o forse giù nel renderer.

Come un work-around è possibile impostare la larghezza della linea a 0:

label.set_bbox({"facecolor": "white", "edgecolor": "None","alpha":0.65, 'lw':0}) 

che farà in modo che la linea non verrà disegnata, indipendente da ciò che il colore/alfa è.

Il modo in cui funziona il codice, si passa set_bbox a dict che viene quindi memorizzato in _bbox. Al momento sorteggio, se _bbox non è None (e non c'è _bbox_patch) _bbox viene passato alla patches.bbox_artist che è una funzione (etichettato come una funzione di debug nella docstring!), Che utilizza il dict per generare un oggetto Rectangle al volo (che non viene restituito!). Un posto nel set_* e nel draw nel rettangolo è dove si trova il bug.

Problemi correlati