PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : pgfplots: colormap anpassen - scharfer Farbübergang bei Nulldurchgang !?



fünfhaus
22-03-2014, 13:17
Hallo,

bin gerade auf folgendes Problem gestoßen: Ich bräuchte eine colormap, die einen scharfen Farbübergang beim Nulldurchgang hat. Minimalbsp.:



\documentclass{article}
\usepackage[ngerman]{babel}
\usepackage[utf8]{inputenc}
\usepackage{pgfplots}
\usepackage{blindtext}
\pgfplotsset{grid style={dashed}}

\begin{document}

\blindtext
%
\begin{figure}[htb]
\centering
\begin{tikzpicture}[scale=1.25]
\pgfplotsset{colormap={blackwhite}{[1pt]
rgb255(0pt)=(255, 200, 0);
rgb255(421pt)=(255, 75, 0);
rgb255(421pt)=(0, 100, 255);
rgb255(1000pt)=(0, 255, 255)}}
\begin{axis}[grid=major,colorbar]
\addplot3[surf,domain=-1:+1,samples=25] {exp(-x^2-y^2)-0.5};
\end{axis}
\end{tikzpicture}
\caption{Bildunterschrift}
\end{figure}
%
%
\blindtext

\end{document}


Hab einfach solange an den pt's rumgeschraubt, bis es eigentlich gut passt. Frage: Gibt es eine elegantere und schnellere Methode? Vielleicht einen Option? Oder ist das die einzige Möglichkeit, den Verlauf anzupassen?

Liebe Grüße

fünfhaus

Feuersaenger
22-03-2014, 16:17
Hi fünfhaus,

Im Prinzip ist Dein Ansatz der Richtige; es gibt keine Option der Art "nutze bitte eine andere colormap, sobald der Wert <0 ist".

Allerdings kann man Deinen Ansatz durch einen Kniff so verbessern, dass Du nicht durch trial und error auf die richtige colormap koordinate kommen musst: Du kannst mit 'point meta min' und 'point meta max' den Bereich angeben, der fuer die colormap/colorbar verwendet wird.

Aufgrund Deiner Funktion kann man sofort sagen, dass point meta max=exp(0)-0.5 = 0.5. Man kann auch ausrechnen, dass point meta min<= exp(-2)-0.5 = -0.364664716763387 . Im Grunde ist es nicht so schlimm, wenn man da einen kleineren Wert als point meta min nimmt. Das ist die Kernidee: wir waehlen point meta min einfach so, dass Du den colormap uebergang "auf 0 eichen" kannst.

Sprich: wir nehmen den Bereich -0.5 : 0.5 . Dann ist die "0" genau in der Mitte. "Die Mitte" heisst, das die colormap Koordinate gerade 500 ist.

Ich wuerde empfehlen, dass Du mindestens einen Punkt abstand beim Uebergang einfuegst - nicht, dass sonst mal eine division durch Null auftritt.

Wir haetten damit


\pgfplotsset{colormap={blackwhite}{[1pt]
rgb255(0pt)=(255, 200, 0);
rgb255(500pt)=(255, 75, 0);
rgb255(501pt)=(0, 100, 255);
rgb255(1000pt)=(0, 255, 255)},
point meta min=-0.5, % ~ exp(-2)-0.5,
point meta max=0.5,}


Das sollte die Sache wesentlich vereinfachen, denke ich.

Beim Bearbeiten ist mir aufgefallen, dass am Uebergang eine unschoene gezackte Linie entsteht. Klar, das liegt am Sampling: wenn wir das auf einem Gitter auswerten und dann verbinden, gibt es sowas.

ABER: da Deine Funktion rotationssymmetrisch ist, koennte man das ganze auch in Polar koordinaten machen! Dann gaebe es keinen gezackten Uebergang. Im Grunde ist es nicht kompliziert, man muss nur aufpassen, dass man tatsaechlich das Bild nicht (wesentlich) aendert. Ich habe das mal fuer Dich gemacht; Du kannst entscheiden, ob Du das gebrauchen kannst oder nicht. Nochmal: Die Polarkoordinaten sind *unwichtig* fuer Deine eigentliche Frage, dies ist mehr ein potentielles Sahnehaeubchen.

Hier also die Idee: polarkoordinaten in 3d haben die Form (winkel, radius, z wert) . In Deinem Fall braeuchten wir winkel im Bereich 0:360 . Der Radius muesste so beschaffen sein, dass das Eingabegebiet dem Bereich -1:1 entspricht und die Funktion dieselben Werte annimmt. Nun, die Funktion laesst sich aufgrund ihrer Symmetrie sehr einfach in Polarkoordinaten angeben: der Radius ist immer r= sqrt(x^2 + y^2). Damit ist -x^2-y^2 = -r^2 . Wir muessen nur noch den Bereich -1:1 abbilden. Der maximale Radius waere fuer x=1, y=1 erreicht, d.h. r=sqrt(1^2+1^2) = sqrt(2). Folglich haben wir die Funktion

(winkel, radius, exp(-radius^2) -0.5)
wobei winkel=0:360, radius=0:sqrt(2) zu waehlen ist.

Zusammengenommen ergibt das das untenstehende Bild:



\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{grid style={dashed}}

\begin{document}

\pgfplotsset{colormap={blackwhite}{[1pt]
rgb255(0pt)=(255, 200, 0);
rgb255(500pt)=(255, 75, 0);
rgb255(501pt)=(0, 100, 255);
rgb255(1000pt)=(0, 255, 255)},
point meta min=-0.5, % ~ exp(-2)-0.5,
point meta max=0.5,}
\begin{tikzpicture}[scale=1.25]
\begin{axis}[grid=major,colorbar]
\addplot3[surf,domain=0:360,z buffer=sort,domain y=0:sqrt(2),data cs=polar,samples=25] {exp(-y^2)-0.5};
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}[scale=1.25]
\begin{axis}[grid=major,colorbar]
\addplot3[surf,domain=-1:+1,samples=25] {exp(-x^2-y^2)-0.5};
\end{axis}
\end{tikzpicture}
\end{document}


Das Resultat habe ich als Bild angehaengt; es enthaelt zunaechst meine Polarkoordinatendarstellung und dann unten Deine alte Funktion.

Von den Optionen her ist lediglich noch folgendes zu erlaeutern:

data cs=polar sagt pgfplots, dass es mit eingabekoordinaten der Form X=winkel, Y=radius, Z = wert umzugehen hat
z buffer=sort ist notwendig, da die automatische tiefensortierung nur fuer kartesische koordinaten klappt


Wie gesagt, falls Du "Sahnetoertchen" nicht magst, brauchst Du es nicht.

Gruss

Christian

fünfhaus
23-03-2014, 18:51
Danke für den Hinweis mit dem "point meta min" und "point meta max"! Hab das erst nach ein paar mal probieren verstanden, was da eigentlich der Trick ist. Das ist gut ;) Also nochmal zusammengefasst:



\pgfplotsset{colormap={blackwhite}{[1pt]
rgb255(0pt)=(255, 200, 0);
rgb255(500pt)=(255, 75, 0);
rgb255(501pt)=(0, 100, 255);
rgb255(1000pt)=(0, 255, 255)},
point meta min=-1, %
point meta max=1}


Die Obergrenze von 0pt, 500pt, 501pt, 1000pt (also die 1000pt) kann beliebig gewählt werden. Hauptsache der zweite Eintrag ist genau die Hälfte von der Obergrenze. Also hier 500pt. Andere Möglichkeit wäre 0pt, 250pt, 251pt, 500pt. Wichtig ist dann, dass das lokale Minimum und Maximum der Funktionswerte (Messdaten) innerhalb von "point meta min" und "point meta max" liegen und die Werte symmetrisch gewählt werden. Liegt also das Min der Funktion bei -0,2 und das Max bei 1,4 funktioniert z.B. point meta min=-2 und point meta max=2 oder point meta min=-10 und point meta max=10. Die Extremalwerte kann man sich mit Matlab oder GNU Octave ja leicht ausgeben lassen. Ich schreib mir die Werte übrigens in den Dateinamen. So kann man dann die Daten auch noch Tage später gut im Latexdokument mit pgfplots verarbeiten.

Das mit den Polarkoordinaten kann ich leider nicht auf meine Messdaten übertragen. Da war mein Minimalbsp wohl zu speziell. Danke trotzdem.

Liebe Grüße

fünfhaus

Feuersaenger
24-03-2014, 22:25
Hi fünfhaus,

ja, gut verallgemeinert.

Es sei noch angemerkt, was passiert, wenn der durch 'point meta min' und 'point meta max' angegebene Bereich nicht zu den eigentlichen Daten passt:

Wenn man naemlich 'point meta max=0.5' sagt, die Funktion aber, sagen wir, den Wert 10 annimmt, wird alles, was oberhalb von 0.5 liegt, mit der "maximalen Farbe" gezeichnet. Genau dasselbe passiert auch der unteren Grenze.

Umgekehrt, wenn ich sage 'point meta max=10', die Funktion aber nur bis maximal 0.5 geht, dann sind grosse Teile der colormap schlichtweg unbenutzt.

In der Hoffnung, sinnvolles beigetragen zu haben,

Christian

fünfhaus
29-03-2014, 12:35
Ja, danke Dir nochmal. Falls ich die Zeit finde, poste ich hier mal ein Minibsp.

Liebe Grüße

fünfhaus