2013-06-03 3 views
7

Ich habe ein seltsames Problem. Mit IPython Notebook habe ich ein ziemlich umfangreiches Skript erstellt, das mit pandas und matplotlib eine Reihe von Diagrammen erstellt. Als mein Basteln abgeschlossen war, kopierte ich (und bereinigte) den Code in ein eigenständiges Python-Skript (so dass ich es in den SVN schieben kann und meine Papier-Co-Autoren können die Diagramme auch erstellen).Warum ist Matplotlib-Plot von Ipython Notebook etwas anders als Terminal-Version produziert?

Die Einfachheit halber habe ich das Standalone-Python-Skript in das Notebook wieder importieren und eine Reihe von Diagrammen erstellen:

import create_charts as cc 
df = cc.read_csv_files("./data") 
cc.chart_1(df, 'fig_chart1.pdf') 
... 

Seltsam genug, die PDF-Datei, die ich unter Verwendung der obigen Verfahren erhalten ist etwas anders als die. pdf-Datei bekomme ich, wenn ich mein eigenständiges Python-Skript von meinem Windows 7-Terminal aus starte. Der auffälligste Unterschied ist, dass in einem bestimmten Diagramm die Legende in der oberen Ecke statt in der unteren Ecke liegt. Aber es gibt auch andere kleine Unterschiede (Bounding Box Größe, Schriftart scheint etwas anders)

Was könnte die Ursache dafür sein. Und wie kann ich es beheben? (Ich schließe schon mein Notebook und neu gestartet, mein create_charts Skript erneut zu importieren und alle nicht gespeicherten Änderungen ausschließen) Berichte Mein Terminal I Python bin mit 2.7.2 und pip freeze | grep ipython Berichte ipython 0.13.1

Antwort

3

Erweitern Matts Antwort (viel Kredit für ihn, aber ich denke, die Antworten können weniger komplex sein), so habe ich es schließlich gelöst.

(a) Ich habe die Standard-Matplotlib-Einstellungen von ipython in C:\Python27\Lib\site-packages\IPython\zmq\pylab\backend_inline.py nachgeschlagen (siehe Matts Antwort).

(b) und überschrieb sie mit den Werten, wie in der Terminalversion gesetzt (I verwendet print mpl.rcParams['figure.figsize'] usw. zu erfahren), indem Sie den folgenden Code in meinem Skript einfügen:

import matplotlib as mpl 

#To make sure we have always the same matplotlib settings 
#(the ones in comments are the ipython notebook settings) 

mpl.rcParams['figure.figsize']=(8.0,6.0) #(6.0,4.0) 
mpl.rcParams['font.size']=12    #10 
mpl.rcParams['savefig.dpi']=100    #72 
mpl.rcParams['figure.subplot.bottom']=.1 #.125 
+0

Beachten Sie, dass Sie die MPL-Einstellungen einfach überschreiben, anstatt zu verhindern, dass IPython sie ändert, wie von Matt vorgeschlagen. –

+0

@hans: vielleicht. Aber es erreicht das Ziel meiner Frage: Sicherstellen, dass die Dinge gleich aussehen. – Rabarberski

2

Die Schriftgröße Probleme sind auf Unterschiede in der dpi zurückzuführen. Ich nehme an, dass die etwas andere Größe der Figur (in Pixeln) die "beste" Position für die Legende ändert.

Die Standard-dpi-Zahl wird bei 80 angezeigt, während savefig standardmäßig auf 100 gesetzt ist. Dies bedeutet, dass die matplotlib-Werte beim Speichern im Vergleich zu den auf dem Bildschirm angezeigten Werten leicht abweichen.

Ich weiß es nicht sicher, aber ich vermute, dass ipython notebooks die dpi auf etwas anderes als 100 setzen (am wahrscheinlichsten 80) und das beim Speichern von Zahlen verwenden.

Versuchen Sie savefig('filename.pdf', dpi=80) in Ihrem Standalone-Skript.

+0

Diese vielversprechend schienen, aber Bis jetzt hilft es nicht. Und wenn ich 'fig.get_dpi()' (vor 'savefig (...)' oder offensichtlich) schreibe, zeigen sowohl Ipython als auch das Terminal "80" an. Ich werde versuchen, morgen herauszufinden, ob die dpi tatsächlich in einer anderen Weise zu beschuldigen ist. (Vorerst habe ich meinen Code aktualisiert, um die Legende so positionieren zu können, wie ich es für dieses einzelne Diagramm möchte) – Rabarberski

+0

Nun, das 'fig.get_dpi()' vor und nach 'savefig' wird nicht helfen, wie' savefig' das nicht tut berühre 'fig.dpi' überhaupt (und ignoriere es tatsächlich). Viel Glück, auf jeden Fall! Ich würde immer noch vermuten, dass es ein DPI-Problem ist, aber die genaue Lösung kann ein bisschen komplexer sein. –

7

Zur Vervollständigung Joe Antwort, die inlinebackend (IPython/kernel/ZMQ/pylab/backend_inline.py) einige Standard matplotlib Parameter haben:

# The typical default figure size is too large for inline use, 
# so we shrink the figure size to 6x4, and tweak fonts to 
# make that fit. 
rc = Dict({'figure.figsize': (6.0,4.0), 
    # play nicely with white background in the Qt and notebook frontend 
    'figure.facecolor': 'white', 
    'figure.edgecolor': 'white', 
    # 12pt labels get cutoff on 6x4 logplots, so use 10pt. 
    'font.size': 10, 
    # 72 dpi matches SVG/qtconsole 
    # this only affects PNG export, as SVG has no dpi setting 
    'savefig.dpi': 72, 
    # 10pt still needs a little more room on the xlabel: 
    'figure.subplot.bottom' : .125 
    }, config=True, 
    help="""Subset of matplotlib rcParams that should be different for the 
    inline backend.""" 
) 

Da dies nicht für jedermann offensichtlich ist, können Sie es in Konfiguration durch c.InlineBackend.rc.

[Bearbeiten] genaue Informationen über die Konfigurierbarkeit.

IPython haben die Besonderheit, dass die meisten Klassen über Eigenschaften verfügen, deren Standardwerte konfiguriert werden können.Diese werden oft als Configurable (Groß C) verweist, kann diese Eigenschaft leicht in dem Code erkennen, da sie wie so erklärt werden, bevor __init__:

property = A_Type(<default_value>, config=True , help="a string") 

Sie diese Eigenschaften in IPython Konfigurationsdateien überschreiben kann (das ist, hängt von was Sie), indem Sie

c.ClassName.propertie_name = value 

hier tun wollen, wie es ein dict ist könnten Sie tun

#put your favorite matplotlib config here. 
c.InlineBackend.rc = {'figure.facecolor': 'black'} 

I Erraten ein leeres Diktat würde es dem Inline-Backend ermöglichen, die matplotlib-Standardwerte zu verwenden.

+0

Ich bin mir nicht sicher, was ich mit dem von Ihnen vorgeschlagenen 'c.InlineBackend.rc' machen soll; Ich habe es in eine 'matplotlibc'-Datei geschrieben, aber das hat mir einen 'Illegalen Zeilenfehler' gegeben. Es ist mir jedoch gelungen, zwei identische Ausgaben zu erhalten, indem ich die Einstellungen in der 'C: \ Python27 \ Lib \ Site-Pakete \ IPython \ zmq \ pylab \ backend_inline.py' Datei durchsuche (die Face/Edgecolors sind nicht in meinem Datei) und Einfügen von ihnen an der Spitze von meinem Python-Skript mit 'mpl.rcParams ['Figure.figsize'] = (6.0.4.0)' und 'mpl.rcParams ['font.size'] = 10' usw. Vielleicht a gute Idee, deine Antwort so zu bearbeiten, dass sie diese Lösung enthält (zB mit rcParams)? – Rabarberski

+0

Kommentar zu rc und IPython config hinzugefügt. Aber es ist ein so komplexes Thema, dass ich nicht wirklich auf Einzelheiten eingehen kann, wie es funktioniert. Es ist eine Art Standardwert, der in einigen Fällen matplotlib rc überschreibt .... – Matt

+0

Ich verstehe nicht, warum Sie sagen, dass es so komplex ist. Ich habe meine endgültige Lösung als separate Antwort hinzugefügt ... – Rabarberski