Sehr oft müssen wir Punkte zeichnen. Jeder von uns hat seine bevorzugte Methode, dies zu tun.
Was ist dein ?
Verwenden Sie Knoten, Bilder, Markierungen usw.? In einem Stil?
Einige Hintergründe
Im Tikz/PGF-Handbuch wird dies sehr oft durch erledigt \tikz\fill circle (2pt);
.
Im Beispiel des Schlüssels /tikz/insert path
sehen wir diesen Code
\tikz [c/.style={insert path={circle[radius=2pt]}}]
\draw (0,0) -- (1,1) [c] -- (3,2) [c];
Es gibt auch ein Beispiel für dieSchlüsselhandler /.pic
(S. 255), um den gleichen ausgefüllten Kreis zu erzeugen.
Diese Methoden haben den Vorteil, dass sie wirklich einfach sind, sind für mich aber nicht gut, weil:
- Das Aussehen des Punkts hängt von der Pfadbefehlsaktion (Zeichnen, Füllen, ...) ab.
- Beim Skalieren des Bildes wird nicht die Linienbreite (und auch nicht die Schriftgröße) skaliert, sondern die Punkte (dies lässt sich leicht umgehen, indem Sie
em
beispielsweise die Größe eingeben). - Wenn Sie nach dem Zeichnen des Punkts eine Linie zeichnen, wird die Linie über den Punkt gezeichnet.
Und mehr ...
Was ich suche
Hier ist eine Liste von Dingen, die ich mit nur einer Definition von „Punkt“ (oder mit mehr als einer Definition, aber mit konsistenter Syntax) tun möchten.
Für jede Anforderung habe ich einen Test zum Bestehen mit dem erwarteten Ergebnis angegeben. Im Test können Sie "Punkt" durch Ihre bevorzugte Syntax ersetzen.
1) Punkte müssen richtig skaliert werden. Und mir ist nicht klar, ob die Größe proportional zur Linienbreite oder zur Schriftgröße sein soll. Wahrscheinlich ist es am besten, die Größe anhand der Linienbreite zu bestimmen und dann bei Bedarf (siehe Punkt 3)) die Größe anpassen zu können, em
wenn wir eine skalierungskompatibilität der Schrift wünschen. Was meinen Sie?
\begin{tikzpicture}
\foreach[count=\i] \w in {ultra thin, thin, ultra thick} {
\draw[yshift=-\i em, \w] (0,0) -- (.5,0) "point" -- (1,0);
}
\foreach[count=\i] \s in {.2, .5, 1} {
\draw[xshift=1.5cm, yshift=-\i em, scale=\s] (0,0) -- (.5,0) "point" -- (1,0);
}
\end{tikzpicture}
2) Wir sollten in der Lage sein, Punkte einfach zu gestalten. Wir sollten zum Beispiel etwas sagen können wie „zeichne einen dicken roten Punkt“.
(zum Test siehe nächsten Punkt)
3) Zeichnen, Füllen und Deckkraft von Punkten können auf eingestellt werden inherit
. In diesem Fall werden diese Parameter vom Bereich/Pfad übernommen. Aber nur das Zeichnen sollte inherit
standardmäßig auf eingestellt werden, die anderen Standardwerte (persönlicher Geschmack) sollten Füllen=weiß und Deckkraft=1 sein.
\begin{tikzpicture}[scale=2, very thick]
\filldraw[draw opacity=.5, draw=red, fill opacity=.3, densely dotted]
(0,0) "point" -- (.5,0) "ultra thick point filled in green" -- (.5,.5) "point with inherited draw, fill and opacity" -- cycle;
\end{tikzpicture}
4) Der Punkt könnte einfach an der zu verwendenden Stelle benannt werden coordinate
, und wenn der Punkt mit dem Namen gezeichnet wird, node
sollte er auf die Mitte des Knotens und nicht auf den Knoten selbst zeigen.
\begin{tikzpicture}
\draw[very thick] (0,1) "point" -- (1,0) "thick point filled in green with name=A";
\draw[ultra thick, purple] (0,0) "point" -- (A);
\end{tikzpicture}
5) Punkte können in jeder Situation verwendet werden, in der wir normalerweise einen anderen Befehl zum Zeichnen verwenden können. Dies wurde bereits in den vorherigen Beispielen veranschaulicht, aber es wäre schön, wenn wir es mit \node at
und verwenden könnten \coordinate at
(was nicht offensichtlich ist, da at
die aktuelle Koordinate nicht geändert wird).
(zum Test siehe nächsten Punkt)
6) Punkte werden über jede Linie gezeichnet (auf der Vordergrundebene).
\begin{tikzpicture}
\node[left] {A} at (0,1) "ultra thick point";
\coordinate["thick point"] (B) at (1,0);
\draw (A) -- (B);
\end{tikzpicture}
7) Die Lösung darf kein Hack sein, damit die Definition von „Punkt“ (hoffentlich) mit zukünftigen Versionen von Tikz kompatibel ist.
Was ist meine persönliche unvollständige Lösung
Ich werde es als Antwort veröffentlichen.
Antwort1
Methode I(mit Knoten)
\tikzset{
every point/.style = {circle, inner sep={.75\pgflinewidth}, opacity=1, draw, solid, fill=white},
point/.style={insert path={node[every point, #1]{}}}, point/.default={},
point name/.style = {insert path={coordinate (#1)}},
}
und noch ein paar zusätzliche Sachen:
\tikzset{
colored point/.style = {point={fill=#1}},
inherit/.style = {point/.style={insert path={node[circle, inner sep={.75\pgflinewidth}, draw, fill, #1]{}}}}
}
Erfüllt 1.
Befriedigt 2 mit Styling wie diesem
[point={fill=red, very thick}]
Erfüllt teilweise 3. Ich weiß nicht, wie ich
draw opacity=inherit
oder definieren sollfill=inherit
. Ich definiere einen neuen Stilinherit
, der das Ganze neu definiertpoint
, indem eropacity=1
und entferntfill=white
, aber das ist hässlich ;).Erfüllt Bedingung 4 teilweise: Sie können verwenden
point name=A
. Ich würde gerne Anführungszeichen verwenden, um etwas wie Folgendes zu sagen[point={red, "A"}]
, weiß aber nicht, wie das geht.Erfüllt fast Punkt 5: Wir können [Punkt] fast überall platzieren, wie
(A) [point]
, odernode[point, above]{A}
, oder . Kann aber nicht mit odercoordinate[point](A)
verwendet werden (außer wenn Sie sich wie folgt wiederholen )\coordinate at
\node at
\coordinate (A) at (1,1) (A) [point];
Fehleram 6. Ich weiß, dassEs gibt eine Hack-Lösung, um einen Knoten auf der Ebene zu platzieren, was aber im Widerspruch zu 7) steht.
Erfüllt 7.
Der vollständige Code aller Tests und das Ergebnis
\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}
% not clear how to use layers with this method
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
\tikzset{
every point/.style = {circle, inner sep={.75\pgflinewidth}, opacity=1, draw, solid, fill=white},
point/.style={insert path={node[every point, #1]{}}}, point/.default={},
colored point/.style = {point={fill=#1}},
point name/.style = {insert path={coordinate (#1)}},
inherit/.style = {point/.style={insert path={node[circle, inner sep={.75\pgflinewidth}, draw, fill, #1]{}}}}
}
\begin{document}
\begin{itemize}
% ---------------------------------
\item Test 1 : ok.\\[1em]
\begin{tikzpicture}
\foreach[count=\i] \w in {ultra thin, thin, ultra thick} {
\draw[yshift=-\i em, \w] (0,0) -- (.5,0) [point] -- (1,0);
}
\foreach[count=\i] \s in {.2, .5, 1} {
\draw[xshift=1.5cm, yshift=-\i em, scale=\s] (0,0) -- (.5,0) [point] -- (1,0);
}
\end{tikzpicture}
% ---------------------------------
\item Test 2 : ok.
% ---------------------------------
\item Test 3 : partialy ok, there is no good \texttt{inherit}.\\
\begin{tikzpicture}[scale=2, very thick]
\filldraw[draw opacity=.5, draw=red, fill opacity=.3, densely dotted]
(0,0) [point] -- (.5,0) [point={ultra thick, fill=green}] -- (.5,.5) [inherit, point] -- cycle;
\end{tikzpicture}
% ---------------------------------
\item Test 4 : almost ok (using \texttt{point name})\\
\begin{tikzpicture}
\draw[very thick] (0,1) [point] -- (1,0) [point={thick, fill=green, point name=A}];
\draw[ultra thick, purple] (0,0) [point] -- (A);
\end{tikzpicture}
% ---------------------------------
\item Test 5 : almost ok.
% ---------------------------------
\item Test 6 : fails ! (visible in test 4 too)\\
\begin{tikzpicture}
\coordinate (A) at (0,1) (A) node[point=ultra thick, left] {A};
\coordinate (B) at (1,0) (B) [thick, point];
\draw (A) -- (B);
\end{tikzpicture}
\end{itemize}
\end{document}
Methode II(mit Bild)
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
\tikzset{
every point/.style = {radius={\pgflinewidth}, opacity=1, draw, solid, fill=white},
pt/.pic = {
\begin{pgfonlayer}{foreground}
\path[every point, #1] circle;
\end{pgfonlayer}
},
point/.style={insert path={pic{pt={#1}}}}, point/.default={},
point name/.style = {insert path={coordinate (#1)}}
}
Fehlerzu 1. Ich weiß nicht, wie ich Stile vom Pfad zum Bild vererbe. Gibt es einen Stil wie
current path style
?Erfüllt 2. Gleich wie Methode I.
Fehlerzu 3. Wir können es wie bei Methode I formatieren, aber weil (1) fehlschlägt, schlägt (3) fehl.
Erfüllt 4 teilweise. Gleich wie Methode I.
Fehlerzu 5 : da es eineFehler in „Bild“wir können in PGF 3.0 keinen Knoten danach verwenden. Wenn dieser Fehler behoben ist, ist diese Methode bei diesem Test gleichwertig mit der ersten.
Erfüllt 6. Dies ist das Hauptinteresse dieser Methode.
Erfüllt 7.
Der vollständige Code aller Tests und das Ergebnis
\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
\tikzset{
every point/.style = {radius={\pgflinewidth}, opacity=1, draw, solid, fill=white},
pt/.pic = {
\begin{pgfonlayer}{foreground}
\path[every point, #1] circle;
\end{pgfonlayer}
},
point/.style={insert path={pic{pt={#1}}}}, point/.default={},
colored point/.style = {point={fill=#1}},
point name/.style = {insert path={coordinate (#1)}}
}
\begin{document}
\begin{itemize}
\item Test 1 : fails for sizing from path width, scale is ok.\\[1em]
\begin{tikzpicture}
\foreach[count=\i] \w in {ultra thin, thin, ultra thick} {
\draw[yshift=-\i em, \w] (0,0) -- (.5,0) [point] -- (1,0);
}
\foreach[count=\i] \s in {.2, .5, 1} {
\draw[xshift=1.5cm, yshift=-\i em, scale=\s] (0,0) -- (.5,0) [point] -- (1,0);
}
\end{tikzpicture}
\item Test 2 : partialy ok, there is no \texttt{inherit} (at all).
\item Test 3 : fails ! Can't inherit style from path.\\
\begin{tikzpicture}[scale=2, very thick, densely dotted]
\filldraw[draw opacity=.5, draw=red, fill opacity=.3]
(0,0) [point] -- (.5,0) [point={ultra thick, fill=green}] -- (.5,.5) [point] -- cycle;
\end{tikzpicture}
\item Test 4 : almost ok (using \texttt{point name})\\
\begin{tikzpicture}
\draw[very thick] (0,1) [point] -- (1,0) [point={thick, fill=green, point name=A}];
\draw[ultra thick, purple] (0,0) [point] -- (A);
\end{tikzpicture}
\item Test 5 : fails ! (can't put node after [point] )
\item Test 6 : ok.\\
\begin{tikzpicture}
\path (0,1) node[left] {A} coordinate (A) [point=ultra thick];
\coordinate (B) at (1,0) (B) [thick, point];
\draw (A) -- (B);
\end{tikzpicture}
\end{itemize}
\end{document}
Antwort2
Notiz:Ich habe eine kleine Tikz-Bibliothek basierend auf dieser Antwort erstellt und benannt,
nicepoints
die verfügbar ist aufGitHub.
Endlich habe ich eine Methode zum Zeichnen von Punkten, die alle Kriterien erfüllt (auf etwas andere Weise für die Farbvererbung) und sogar noch mehr.
Bevor ich Ihnen die vollständige Lösung gebe, beginnen wir am Anfang der Geschichte.
Der einfachste Weg
Mir ist gerade aufgefallen, dass die beste Möglichkeit, etwas deutlich zu machen, wahrscheinlich die Verwendung eines „Punkts“ ist .
:
\tikz\draw[very thin,red] (0,0) -- node{.} (1,0);
Die Farbe wird meiner Meinung nach auf sehr nützliche Weise übernommen. Die Farbe des Punkts ist die gleiche wie die Textfarbe.
\tikz\draw[very thin,red,text=violet] (0,0) -- node{.} node[above]{A} (1,0);
Für dickere Linien sind solche Punkte jedoch zu klein.
\tikz\draw[very thick,red,text=violet] (0,0) -- node{.} (1,0);
Wir können es mithilfe von skalieren line width
und das Ganze durch die Erstellung eines Stils automatisieren.
\tikzset{point/.style={insert path={ node[scale=2.5*sqrt(\pgflinewidth)]{.} }}}
\tikz\draw[very thick,red,text=violet] (0,0) -- node[point,above]{A} (1,0);
Die Wahl sqrt
ist Geschmackssache: So sind die Punkte bei dünneren Linien nicht zu klein und bei dickeren nicht zu dick. Tatsächlich ist die Oberfläche des Punktes auf diese Weise proportional zur Linienbreite.
Anspruchsvollere Punkte
Und wenn wir den Punkt füllen möchten, können wir einfach einen weiteren, kleineren Punkt über den ersten zeichnen:
\tikzset{
outer dot/.style = {scale=2.5*sqrt(\pgflinewidth)},
inner dot/.style = {scale=sqrt(\pgflinewidth),#1},inner dot/.default={white},
point/.style={insert path={ node[outer dot]{.} node[inner dot=#1]{.}}}
}
\tikz\draw[very thick,blue] (0,0) -- node[point]{} (1,0) [point=red];
Das noch nicht gelöste Problem besteht darin, dass die nach einem Punkt gezeichneten Linien diesen wie folgt überlappen können:
\begin{tikzpicture}[scale=2]
\draw[very thick,blue] (0,0) -- node[point]{} (1,0) [point=red];
\draw[red] (0,0) -- node[point]{} (1,.2);
\draw[very thick] (0,.2) -- (1,0);
\end{tikzpicture}
Die Lösung
Wir möchten den Punkt auf eine obere Ebene setzen, so dass jede Linie, die danach gezeichnet wird, unter dem Punkt bleibt. Dafür können wir verwenden, pgfonlayer
aber es gibt zwei Schwierigkeiten:
Es gibt nicht so viele Möglichkeiten, automatisch einzufügen
pgfonlayer
. Wir können einige Hacks verwenden (aber das möchte ich nicht). Wir können verwendenpic
, aber in diesem Fall müssen wir den Fehler von TikZ 3.0.0 beheben, wenn wir Knoten nach dem Punkt verwenden möchten. Und die dritte Option, die ich kenne, ist die Verwendung vonpath picture
.
Dabei gibt es einen Kniff: Wenn wir durch Ändern der Ebene etwas hineinzeichnenpath picture
, wird die Zeichnung nicht beschnitten, da der Beschnitt auf die ursprüngliche Ebene angewendet wird.Wenn wir die Ebene wechseln, wird "fast" alles zurückgesetzt: die Linienbreite, die Zeichen- und Füllfarben, die Deckkraft. Aber ich war angenehm überrascht, als ich schriebdiese Frage, dass die Textfarbe und Deckkraft durch den Ebenenwechsel nicht zurückgesetzt werden. Das einzige, worauf wir achten müssen, ist also das
line width
. Das ist aber nicht so schwer, da wir zur Verfügung haben,pgflinewidth
dass wir vor dem Ebenenwechsel speichern und auf der neuen Ebene verwenden können.
Hier ist die „nicht zitierte“ Version der Lösung zur ursprünglichen Frage:
\pgfdeclarelayer{points}
\pgfsetlayers{main,points}
\tikzset{
set point size/.code={\pgfmathsetmacro{\pointsize}{sqrt(\pgflinewidth)}},
point size/.style={set point size/.prefix style={line width=#1}},
every dot/.style = {inner sep=0, outer sep=0,font=},
outer dot/.style = {every dot, scale=2.5*\pointsize},
inner dot/.style = {every dot, scale=\pointsize, text=#1}, inner dot/.default={white},
point fill/.style = {inner dot/.default={#1}},
point coordinate/.style={insert path={coordinate(#1)}},
point/.style={insert path={
node[inner sep=0, overlay, every point/.try, #1, set point size,
path picture={
\begin{pgfonlayer}{points}
\node[outer dot]{.} node[inner dot]{.};
\end{pgfonlayer}
}
]{}
}
}
}
Und hier noch ein Test:
\begin{tikzpicture}[scale=2]
\draw[blue] (0,0)[point] -- node[thick,point={name=A},below]{$A$} (1,0) [point=red];
\draw[red] (0,0) -- node[point]{} (1,.2) [point=thick];
\draw[very thick] (0,.2)[point={point coordinate=B, label=$B$}] -- (1,0);
\draw[green] (A)--(B);
\end{tikzpicture}
Wie man ...
- Wie verwendet man
point
Stil?- einfach als
(1,1) [point]
, - oder innerhalb eines anderen Knotens wie diesem
node[point,below]{$A$}
.
- einfach als
- Wie setzt man einen Punkt in die Mitte eines Segments?Wir können keine
-- [point]
Syntax verwenden, aber wir können:- in einen anderen Knoten einfügen, wie folgt
-- node[point]{}
- oder nach dem Ende des Segments, so
--(1,1)[point=midway]
- in einen anderen Knoten einfügen, wie folgt
- Wie stelle ich die
draw
Farbe eines Punktes ein?So legen wir die Textfarbe aller Knoten fest.- Wenn die Farbe auf diese Weise auf dem Pfad festgelegt ist,
\path[red] ...
wird sie an die Punkte auf dem Pfad vererbt (da in diesem Fall auch die Textfarbe festgelegt ist).
\tikz\draw[red] (0,0. -- (1,0) [point=midway];
- Wenn wir für den Pfad/Bereich nur die Zeichen-/Füllfarbe festlegen, nicht jedoch die Textfarbe, sind die Punkte standardmäßig schwarz (wie der Text).
\tikz\path[draw=red] (0,0) -- (1,0) [point=midway];
- Wir können die Punktfarbe wie im folgenden Beispiel angeben:
- Wenn die Farbe auf diese Weise auf dem Pfad festgelegt ist,
\begin{tikzpicture}[Maßstab=2] \draw[fill=blau!14] (0,0) [Punkt] -- (1,0) [Punkt=blau] -- Knoten [rot, Punkt, links] {roter Punkt und Text} (1,1) Knoten [Punkt, über, rot] {nur roter Text} -- (0,1) node[point=red,below]{nur roter Punkt}; \end{tikzpicture}
- Wie stelle ich die
fill
Farbe eines Punktes ein?Durch Verwendungpoint fill
der Taste.- Wenn wir es für alle Punkte auf dem Pfad festlegen möchten, können wir Folgendes tun:
\path[point fill=red] ...
- Wenn wir es für einen Punkt festlegen möchten, können wir dies tun
[point={point fill=red}]
.
- Wenn wir es für alle Punkte auf dem Pfad festlegen möchten, können wir Folgendes tun:
\tikz\path[ultradick, rot, Punktfüllung=blau] (0,0) [Punkt] (.5,0) [Punkt={Punktfüllung=grün}] (1,0) [Punkt];
- Wie stelle ich die Punktgröße ein?Der Punkt erbt seine Größe von der Linienbreite des Pfades.
- Um es für einen Punkt zu ändern, können wir
[point=very thick]
zum Beispiel verwenden - Um es für alle Punkte im Bereich unabhängig von der Linienbreite festzulegen, können wir
point size=.8pt
beispielsweise verwenden
- Um es für einen Punkt zu ändern, können wir
Und schließlich können wir every point
den Standardpunktstil festlegen.
Zusätzliches Zeug: zitierte Punkte
Wenn wir in der Lage sein möchten point="A"
, die Koordinaten festzulegen (A)
und den Text $A$
neben dem Punkt anzuzeigen, können wir die quotes
Bibliothek verwenden.
Hier ist der vollständige Code für diese quoted
Punkte.
\usetikzlibrary{quotes}
\pgfdeclarelayer{points}
\pgfsetlayers{main,points}
\tikzset{
set point size/.code={\pgfmathsetmacro{\pointsize}{sqrt(\pgflinewidth)}},
point size/.style={set point size/.prefix style={line width=#1}},
every dot/.style = {inner sep=0, outer sep=0,font=},
outer dot/.style = {every dot, scale=2.5*\pointsize},
inner dot/.style = {every dot, scale=\pointsize, text=#1}, inner dot/.default={white},
point fill/.style = {inner dot/.default={#1}},
point coordinate/.style={insert path={coordinate(#1)}},
quotes mean point/.style={'/.style={empty label/.style={node contents=}},
node quotes mean/.try={point coordinate=##1,
label={[direction shorthands, every label quotes/.try, ##2,
node contents=\ensuremath{##1}, empty label/.try]}}},
point/.style={quotes mean point, insert path={
node[inner sep=0, overlay, every point/.try, #1, set point size,
path picture={
\begin{pgfonlayer}{points}
\node[outer dot]{.} node[inner dot]{.};
\end{pgfonlayer}
}]{}
}
}
}
So verwenden Sie zitierte Punkte
- Wenn Sie sagen
[point="B"red]
, wird zuerstcoordinate(B)
eingefügt und dann das Äquivalent vonlabel={[red]$B$}
verwendet. - Wenn Sie
[point="B"']
(mit'
) verwenden,$B$
wird nicht angezeigt (leeres Label wird hinzugefügt), sonderncoordinate(B)
eingefügt. - Wenn wir nur eine Beschriftung ohne Koordinate möchten, können wir
[point={label=$B$}]
oder verwendennode[point,above]{$B$}
.
Beenden wir diese kurze Antwort mit einem Anwendungsbeispiel für „zitierte Punkte“:
\begin{tikzpicture}[scale=2]
\draw[fill=yellow!30,very thick]
(0,0) [point="A"] -- (1,0) [point={"B"',blue}]
-- node[red,point="C"left]{} (1,1) [point="D"{above,red}]
-- (0,1) [point={red,"E"}];
\draw[thick,purple] (E) -- (B) to[bend right] (D) edge[bend right] (C) [point=near start];
\end{tikzpicture}
AKTUALISIEREN:Wir können \point
wie folgt definieren
\def\point[#1] at (#2){\path (#2) [point={#1}]}
und dann verwenden Sie es wie folgt:
\point["A"below] at (1,1);
UPDATE 2:Nach den Kommentaren von PaulGaborit habe ich every dot
einen Stil hinzugefügt, der die Schriftart zurücksetzt. Wenn wir also eine Schriftart mit einem Punkt verwenden, der nicht in der Mitte des Knotens zentriert ist, haben wir zwei Möglichkeiten:
- erzwingen, dass die Schriftart "dot" die Standardschriftart ist,
- oder nehmen Sie eine Verschiebung (in em) vor, um es in die Mitte zu setzen.
Wir können zum Beispiel Folgendes eingeben:
\tikzset{
every dot/.style={inner sep=0, outer sep=0,
node font=\usefont{T1}{lmr}{m}{n}\fontsize{10pt}{0pt}\selectfont}
}