Seite 1 von 2

pgfplots: Torus, Möbiusband und Klein'sche Flasche plotten

Verfasst: So 4. Dez 2011, 14:06
von guy.brush™
Hallo,

ich möchte folgendes plotten: Torus, Möbiusband und Klein'sche Flasche.

Ich habe mich dabei an die Funktionsvorschriften von Wikipedia gehalten. Aber irgendwie mag das ganze nicht so funktionieren (siehe Output meines Minimalbeispiels). Wikipedia behauptet zwar, es seien kartesische Koordinaten und keine Polarkoordinaten ... ich bin aber irgendwie verwirrt, denn man gibt ja Winkel an ... aber ich bin gerade eh so durcheinander, dass ich nicht mehr sagen kann, welche Koordinaten es sind ;).

Wo liegt mein Fehler denn? Kann mir da vielleicht jemand helfen?

Und: Ich habe Linux, recht aktuell gehalten, und nutze TeXLive. Wenn ich die library "polar" hinzupacke, findet er die Datei nicht:
(/usr/share/texmf-dist/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrary
plotmarks.code.tex
File: tikzlibraryplotmarks.code.tex 2008/01/09 v2.10 (rcs-revision 1.1)

(/usr/share/texmf-dist/tex/generic/pgf/libraries/pgflibraryplotmarks.code.tex
File: pgflibraryplotmarks.code.tex 2010/10/15 v2.10 (rcs-revision 1.12)
)))
! I can't find file `pgflibrarypgfplots.polar.code.tex'.
<to be read again>
\relax
l.12 \usepgfplotslibrary{polar}

(Press Enter to retry, or Control-D to exit)
Please type another input file name
! Emergency stop.
<to be read again>
\relax
l.12 \usepgfplotslibrary{polar}

*** (job aborted, file error in nonstop mode)
Ist die etwa nicht in TeXLive enthalten? ["groupplots" kannte er, "patchplots" hingegen wieder nicht ... mehr habe ich aber auch nicht getestet.]

Hier das Beispiel (der 2. Plot soll nur zeigen, dass generell alles toll funktioniert, wenn man ein Beispiel aus dem Handbuch nimmt :)):
\documentclass[a4paper,%
	       11pt]{scrartcl}

\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage[utf8]{inputenc}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{matrix,arrows,calc,intersections}
\usepackage{pgfplots}
% \pgfplotsset{compat=1.3}
% \usepgfplotslibrary{polar}

\begin{document}

\begin{tikzpicture}
  \centering
  \begin{axis}[axis x line=left, axis y line=left, axis line style={->}]%, every outer y axis line/.append style={->}]
    \centering
    \addplot[smooth] coordinates {
      (0,0) (1,1) (2,5) (3,1)
      (4,7) (5,1)
    };
  \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
  \begin{axis}[height=10cm, scatter]
%     \addplot3[surf, faceted color=black, domain=1:100, y domain=1:10] {y};
    \addplot3[surf,z buffer=sort,samples=20,domain=-1:0,y domain=0:2*pi]
		      ({sqrt(1-x^2) * cos(deg(y))},
		      {sqrt( 1-x^2 ) * sin(deg(y))},
		      x);

  \end{axis}

\end{tikzpicture}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand{\radius}{2}
    \newcommand{\Radius}{3}
    \begin{axis}[height=10cm]
      \addplot3[surf, domain=0:16.28]
			({(\Radius + \radius * cos(y)) * cos(x)},
			{(\Radius + \radius * cos(y)) * sin(x)},
			{\radius * sin(y)});

    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \begin{axis}[height=10cm]
      \addplot3[surf,domain=0:6.28]
			({2 * (1 - sin(x)) * cos(x) + (2 - cos(x)) * cos(y) * (2 * exp(0-(x/(2 - pi)^2)) - 1)},
			{(2 - cos(x)) * sin(y)},
			{6 * sin(x) + 0.5 * (2 - cos(x)) * sin(x) * cos(y) * exp(0-((x - 3 * pi)/2)^2)});

    \end{axis}
  \end{tikzpicture}
  \caption{Klein'sche Flasche}
\end{figure}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \begin{axis}[height=10cm]
      \addplot3[surf,domain=-1:1, y domain=0:6.28]
			({cos(y) * (1 + x/2 * cos(y/2))},
			{sin(y) * (1 + x/2 * cos(y/2))},
			{x/2 * sin(y/2)});

    \end{axis}
  \end{tikzpicture}
  \caption{M"obiusband}
\end{figure}

\end{document}

Kurze Frage nebenbei, weil ich dafür nicht ein extra Thema aufmachen möchte: Warum genügt
axis line style={->}
nicht, um auch bei der y-Achse einen (imho schöneren) LaTeX-Pfeil wie bei der x-Achse zu bekommen?


Viele Grüße,

\\ guy.brush

Verfasst: So 4. Dez 2011, 20:09
von guy.brush™
Also ich konnte herausfinden (durch testen), dass die pgfplots-Version bei TeXLive aktuell nicht aktuell genug ist. Durch manuelles Installieren konnte ich die neueste Version von pgfplots installieren, allerdings auf Kosten der Paketgruppe "texlive-pictures" ... was auch immer darunter alles fällt.

Leider klappt es immer noch nicht. Ich denke also, dass entweder ein mathematischer Fehler, den ich aber gerade nicht sehe, oder ein Syntax-Fehler, den ich ebenfalls nicht sehe, vorliegt.

Ich gehe davon aus, dass in allen 3 Fällen derselbe Fehler vorliegt. Wer mir also helfen kann/möchte, so wäre der Torus mein Lieblingsobjekt, das ich gerne zuerst plotten können würde :).


Edit: Ok, ich denke, dass es an mir liegt bzw. an einem Syntax-Fehler oder Ähnlichem, aber ich schaffe es nicht einmal, eine Kugel zu plotten:
\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand{\radius}{2}
    \newcommand{\Radius}{3}
    \begin{axis}[height=10cm]
      \addplot3[surf, data cs=cart,domain=0:pi, y domain=0:2*pi]
			({\radius * sin(x) * cos(y)},
			{\radius * sin(x) * sin(y)},
			{\radius * sin(y)});
    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure}
Was mache ich nur falsch?

Verfasst: So 4. Dez 2011, 21:01
von cgnieder
Ein Problem scheint zu sein, dass Du den trigonometrischen Funktionen die Koordinaten im Gradmaß geben musst. Das hier sieht brauchbar aus:
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgfplots}
\pgfplotsset{compat=1.4}
\begin{document}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand*\radius{2}
    \newcommand*\Radius{4}
    \begin{axis}[view={60}{30}]
      \addplot3[surf, domain=0:2*pi,z buffer=sort]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \begin{axis}
      \addplot3[surf,domain=-1:1,y domain=0:2*pi,z buffer=sort]
         ({cos(deg(y)) * (1 + x/2 * cos(deg(y)/2))},
         {sin(deg(y)) * (1 + x/2 * cos(deg(y)/2))},
         {x/2 * sin(deg(y)/2)});
    \end{axis}
  \end{tikzpicture}
  \caption{M"obiusband}
\end{figure}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand*\breite{3}
    \newcommand*\hoehe{8} 
    \begin{axis}
      \addplot3[surf,domain=0:2*pi,z buffer=sort]
         ( { \breite * ( 1 - sin(deg(x))) * cos(deg(x)) + (2 - cos(deg(x))) * cos(deg(y)) * ( 2 * exp(-(x/2 - pi)^2) -1 ) } ,
           { ( 2 - cos(deg(x)) ) * sin(deg(y)) } ,
           { \hoehe * sin(deg(x)) + .5 * ( 2 - cos(deg(x)) ) * sin(deg(x)) * cos(deg(y)) * exp(-(x -3*pi/2)^2) } );
    \end{axis}
  \end{tikzpicture}
  \caption{Klein'sche Flasche}
\end{figure}

\end{document}

Verfasst: So 4. Dez 2011, 22:10
von guy.brush™
Hallo,

ahhh ... vielen Dank! :) Genauer sagen kannst du aber vermutlich nicht, wieso dem so ist, oder?

Das "deg(...)" hatte ich irgendwo schon in einem Beispiel gelesen ... aber ich habe nicht weiter darüber nachgedacht - außerdem steht "deg" bei mir für die Funktion, die den Grad eines Polynoms/einer Funktion zurückgibt *g*.

Zwei Fragen wären aber noch offen bzw. haben sich weiter ergeben:

Was macht genau "z buffer" und dementsprechend dann auch "z buffer=sort"? Ich habe das im Handbuch nicht so genau verstanden dazu, eigentlich so ziemlich gar nicht verstanden :).

Die zweite Frage wäre: Ich würde gerne einen Torus herausbekommen, der ähnlich aussieht wie dieser hier, sprich großes Loch in der Mitte, kleiner Radius im "Hauptbereich" des Torus. Meine angegebenen Werte im Beispiel (das gleich folgt) sollten eigentlich so etwas erreichen, aber pgfplots verzerrt automatisch die Achsen, weshalb es etwas komisch aussieht. Eine andere Skalierung oder 1:1-Beziehung (also unverzerrte Achsen) sollten da schon helfen, aber das bekomme ich gerade nicht hin :).
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgfplots}
\pgfplotsset{compat=1.4}
\begin{document}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand*\radius{1}
    \newcommand*\Radius{6}
    \begin{axis}
      \addplot3[surf, x=1cm,y=1cm,z=5cm,domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure}
So scheint das leider nicht zu funktionieren :).


Viele Grüße,

\\ guy.brush

PS: Das Paket "pgfplots" scheint echt sehr nett zu sein. Schade, dass TeXLive, wieso auch immer, nicht die aktuelle Version beinhaltet.

Verfasst: So 4. Dez 2011, 22:45
von cgnieder
guy.brush™ hat geschrieben:Genauer sagen kannst du aber vermutlich nicht, wieso dem so ist, oder?.
Ich hab das bei den Beispielen im Manual S. 89 gesehen und bin dann davon ausgegangen, dass die trigonometrischen Funktionen bei pgfplot offenbar Gradmaß benötigen. Hab ich nicht weiter drüber nachgedacht...
guy.brush™ hat geschrieben:Was macht genau "z buffer" und dementsprechend dann auch "z buffer=sort"? Ich habe das im Handbuch nicht so genau verstanden dazu, eigentlich so ziemlich gar nicht verstanden :).
Ich hab vorhin zum ersten Mal pgfplots verwendet, kenne also keine Details. Im Manual steht zu Beginn des Teils über 3d-plots, dass man bei parametrischen Oberflächen "sort" nehmen sollte, deshalb hab ich's rein gemacht.
Another issue which arises in three dimensional visualization is depth. pgfplots supports z buffering techniques up to a certain extend. It works pretty well for single scatter plots (z buffer=sort), mesh or surface plots (z buffer=auto) or parametric mesh and surface plots (z buffer=sort). However, it can’t combine different \addplot commands, those will be drawn in the order of appearance.
Es scheint aber mit der Reihenfolge, in der die Punkte im Plot gezeichnet werden, zu tun haben.
This key allows to choose between different z buffering strategies. A z buffer determines which parts of an image should be drawn in front of other parts.
Die Skalierungskeys x,y und z sind Argumente der axis Umgebung (siehe S. 190 im Manual), und nicht von \addplot:
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgfplots}
\pgfplotsset{compat=1.4}
\begin{document}

\begin{figure}
  \centering
  \newcommand*\radius{1}
  \newcommand*\Radius{6}
  \begin{tikzpicture}
    \begin{axis}[x={(-8pt,-2pt)},y={(10pt,0)},z={(0,20pt)}]
      \addplot3[surf,domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \begin{tikzpicture}
    \begin{axis}[x={(-8.66pt,-5pt)},y={(10pt,0)},z={(0,10pt)}]
      \addplot3[surf,domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \begin{tikzpicture}
    \begin{axis}[x={(10pt,0)},y={(0,10pt)},z={(0,0)}]
      \addplot3[surf,domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure} 

\end{document}
guy.brush™ hat geschrieben:PS: Das Paket "pgfplots" scheint echt sehr nett zu sein. Schade, dass TeXLive, wieso auch immer, nicht die aktuelle Version beinhaltet.
Nicht? Ich hab v1.5 in TL2011, dieselbe wie hier...?

Verfasst: Di 6. Dez 2011, 11:21
von guy.brush™
Hallo,

vielen Dank noch einmal für deine Hilfe :). Ich habe jetzt auch noch einmal gelesen, dass gnuplot radian erwartet, der normale weg über pgfplots aber degree.

Zu den x, y und z: Oh, das muss ich dann etwas zu sehr überflogen oder überlesen haben. War am Wochenende quasi so krank, dass ich die Arbeit für die Uni nicht machen konnte, da habe ich mir in 2 Tagen das meiste von pgfplots 'reingeknüppelt ;).

Ich muss aber gestehen, dass ich die Skalierungsvarianten irgendwie überhaput nicht verstehe. Ich glaube, dass das aktuell auch etwas mein Vorstellungsvermögen sprengt (ich bin nicht so super gut im Vorstellen von konkreten Dingen, ich mag lieber kuriose Vorstellungen von abstrakten Dingen :)).

Ich habe aber noch eine andere Möglichkeit gefunden, um den Output anzupassen, die so offensichtlich ist, dass ich sie wohl erst gar nicht gesehen haben: Als optionales Argument hinter \begin{axis} ein [height=42cm, width=13cm] zum Beispiel. Ob das jetzt eine sonderlich schöne Variante ist, weiß ich nicht.

Ich hatte eigentlich auch eher danach gesucht, die jeweiligen Verhältnisse ("1 cm entspricht q Einheiten auf der Achse x, y bzw. z") angeben zu können und somit die Skalierung zu verändern. Vermutlich steckt das hinter der von dir verwendeten Methode.


Ich werde vermutlich wegen ein paar anderen, grundlegenderen Fragen, noch einmal einen Thread zu pgfplots aufmachen, aber das passt thematisch jetzt hier nicht so gut herein. Deshalb setze ich den Status einmal auf "beantwortet", in der Hoffnung, mit meiner Lösung und einem evtl. "view={...}{...}" auch glücklich werden zu können. Sonst frage ich doch noch einmal nach ;).


Vielen Dank noch einmal!

Viele Grüße,

\\ guy.brush

Verfasst: Di 6. Dez 2011, 17:43
von feuersaenger
Hallo guy.brush,

zum Thema "unverzerrte achsen" sollte "axis equal" als option hinter \begin{axis[... " reichen - das hat genau das gewuenschte Verhalten. Dann muss man sich nicht mit 'x=...' rumplagen.

Zu dem z buffer=sort : wie schon richtig angemerkt geht es um die Anforderung, die Graphik in der korrekten Tiefendarstellung anzuzeigen. Konkret: das, was "vorne" ist, wird angezeigt, das, was "hinten" ist, verschwindet hinter den vorderen Bildteilen. Hier ist z buffer=sort eine der technischen Umsetzungen, die fuer parametrische Plots (wie bei Dir) notwendig sind (wie auch schon korrekt angemerkt). Normalerweise ist 'z buffer=sort' teurer als noetig, darum ist es nicht der default. Wenn Du mehr darueber wissen willst, lohnt sich die google suche nach "painter's algorithm" - das ist genau das.

Mit liebem Gruss

Christian

Verfasst: Mi 7. Dez 2011, 14:09
von guy.brush™
Hallo,

eine Antwort vom pgfplots-Meister, ich fühle mich geehrt :). Bei Gelegenheit werde ich mir vermutlich einmal anschauen, wie kompliziert dieser "painter's algorithm" ist, aber in angewandter Mathematik bzw. Numerik und Algorithmen bin ich nicht sonderlich gut und habe ich auch noch nicht so viel mit gemacht :).

Danke erst einmal für die Erklärung mit dem "z buffer=sort".

"axis equal" hilft teilweise wirklich, vielen Dank! Etwas problematisch wird es, wenn man gewisse Werte bei view={...}{...} setzen möchte. Ich habe jetzt auch noch ein bisschen "plot box ratio" herumgespielt, damit bekommt man dann auch teilweise akzeptable bis gute Ergebnisse. Für den Donut habe ich 2 Varianten gefunden (ich möchte, dass es so aussieht, als ob der auf einem Tisch liegt und man von oben schräg draufkommt, er soll also nicht "diagonal" im Raum liegen ... ich hoffe du/ihr versteh(s)t, was ich meine, die Beschreibung ist im 3D-Raum etwas "dürftig" ;)).
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgfplots}
\pgfplotsset{compat=1.4}
\begin{document}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand*\radius{1}
    \newcommand*\Radius{6}
    \begin{axis}[scale=2,view={0}{50},height=4cm,width=7cm]
      \addplot3[surf,domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \newcommand*\radius{1}
    \newcommand*\Radius{6}
    \begin{axis}[scale=1.5,view/v=20,plot box ratio={1 1 0.2}]%[scale=2,view={0}{50},height=4cm,width=7cm]
      \addplot3[surf,domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({(\Radius + \radius * cos(deg(y))) * cos(deg(x))},
         {(\Radius + \radius * cos(deg(y))) * sin(deg(x))},
         {\radius * sin(deg(y))});
    \end{axis}
  \end{tikzpicture}
  \caption{Torus}
\end{figure}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \begin{axis}[axis equal,scale=2,axis lines=none]%[x={(10pt,5pt)},y={(10pt,0)},z={(0,20pt)}]
      \addplot3[surf,domain=-1:1,y domain=0:2*pi,z buffer=sort,opacity=0.75]
         ({cos(deg(y)) * (1 + x/2 * cos(deg(y)/2))},
         {sin(deg(y)) * (1 + x/2 * cos(deg(y)/2))},
         {x/2 * sin(deg(y)/2)});
    \end{axis}
  \end{tikzpicture}
  \caption{M"obiusband}
\end{figure}

\end{document}
Die ersten beiden Fälle zeigen meine anderen Lösungsansätze noch. Ich hoffe, sie würden im Normalfall keine Probleme machen. ich muss aber dazu sagen, dass ich aktuell nur die Form der Plots benötige ohne Achsen. Daher auch noch eine ergänzende Frage:

Beim Möbiusband sieht man es ganz gut. Dort ist ja noch viel (weißer) Platz um das Band herum, insb. erkennt man es zur \caption der figure-Umgebung. Kann ich diesen irgendwie "löschen"? Ich denke, dass die Achsen nicht umsonst so lang sind, auch wenn es so aussieht, als ob die Achsen länger sind als das Möbiusband in die jeweilige Richtung.

Mit \clip außerhalb der axis-Umgebung zu arbeiten, habe ich gerade nicht hinbekommen und würde ich auch als eher umständlichere und "dirty"-Lösung empfinden.


Viele Grüße,

\\ guy.brush

Verfasst: Fr 16. Dez 2011, 11:26
von feuersaenger
Hi guy.brush,

der viele whitespace kommt daher, dass pgfplots auch noch einen clippath "zeichnet" -- und der ist genauso gross wie die (unsichtbare) achse.

Wenn Du 'clip=false' als option zu der Achse hinzufuegst, verschwindet das -- und Du hast als resultat eine enge bounding box ohne zusatzwhitespace.

Das ist nicht naheliegend, daher nehme ich Deine rueckfrage mal als anlass, das ins manual aufzunehmen... die Frage ist nur, wohin. Vielleicht zu dem "axis lines=none" bzw. "hide axis" oder so...

Mit liebem Gruss

Christian

Verfasst: Fr 16. Dez 2011, 14:15
von guy.brush™
Hallo,

auch hier vielen Dank :). "clip=false" erzeugt in der Tat genau das, was ich möchte.

Wobei mir ist gerade nicht klar, was der Unterschied zwischen "axis lines=none" und "hide axis=true" sein soll. Eine Aufnahme mit Beispiel ins manual würde ich auf jedenfall als hilfreich empfinden, ggf. bei "axis lines=none" dann eine Referenz erstellen zu "hide axis=true", wo man dann die genauere Erklärung mit Beispiel findet (oder umgekehrt).

Da mir lediglich nur der Unterschied zwischen den 2 Optionen nicht ganz klar ist, stelle ich trotzdem einmal den Status dieses Threads auf "beantwortet" :).

Viele Grüße,

\\ guy.brush