Painting an ellipse that fits a row of node but is not narrow and long
Here's the "proper" way to do it: Adjust the ellipse
shape. As it is, the circumscribing ellipse has the same height to width ratio H/W
as the rectangle of nodes it circumscribes (A/B
). In this case, H=sqrt(2)*A
and B=sqrt(2)*W
. This, of course, doesn't have to be that way. To get other aspect ratios that circumscribe a rectangle, you can scale the ratio using a factor c
. The height and width of the ellipse then become H=sqrt(c^2+1)*A
and W=sqrt(c^2+1)/c*B
.
The code below declares a new shape called newellipse
that will circumscribe a rectangle (or a set of nodes) just like the standard ellipse, but you can scale its height to width ratio using the key ellipse ratio
. The code
\begin{tikzpicture}[
every node/.style={draw},
every newellipse node/.style={inner sep=0pt}
]
\path node (a) {A} -- ++(2cm,0) node (b) {B};
\node[fit=(a)(b), newellipse] {};
\node[fit=(a)(b), red, newellipse, ellipse ratio=2] {};
\node[fit=(a)(b), blue, newellipse, ellipse ratio=6] {};
\end{tikzpicture}
then yields
Here's the complete code. Only three lines are changed compared to the original ellipse
shape, but unfortunately the whole \radius
command has to be repeated.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit,shapes.geometric}
\makeatletter
\pgfkeys{/pgf/.cd,
ellipse ratio/.code={\pgfkeyssetvalue{/pgf/ellipse ratio}{#1}},
ellipse ratio/.initial=1
}
\pgfdeclareshape{newellipse}
{
\inheritsavedanchors[from=ellipse]
\inheritanchorborder[from=ellipse]
\savedanchor\radius{%
%
% Caculate ``height radius''
%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by.5\dp\pgfnodeparttextbox%
\pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}%
\advance\pgf@y by\pgf@yb%
%
% Caculate ``width radius''
%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
\advance\pgf@x by\pgf@xb%
%
% Adjust
%
\pgfkeysgetvalue{/pgf/ellipse ratio}{\ratioscale}
\pgfmathsetmacro\widthfactor{sqrt(\ratioscale^2+1)/\ratioscale}
\pgfmathsetmacro\heightfactor{sqrt(\ratioscale^2+1)}
\pgf@x=\widthfactor\pgf@x%
\pgf@y=\heightfactor\pgf@y%
%
% Adjust height, if necessary
%
\pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}%
\ifdim\pgf@y<.5\pgf@yc%
\pgf@y=.5\pgf@yc%
\fi%
%
% Adjust width, if necessary
%
\pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}%
\ifdim\pgf@x<.5\pgf@xc%
\pgf@x=.5\pgf@xc%
\fi%
%
% Add outer sep
%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\advance\pgf@x by\pgf@xb%
\advance\pgf@y by\pgf@yb%
}
\inheritanchor[from=ellipse]{center}
\inheritanchor[from=ellipse]{mid}
\inheritanchor[from=ellipse]{base}
\inheritanchor[from=ellipse]{north}
\inheritanchor[from=ellipse]{south}
\inheritanchor[from=ellipse]{west}
\inheritanchor[from=ellipse]{mid west}
\inheritanchor[from=ellipse]{base west}
\inheritanchor[from=ellipse]{north west}
\inheritanchor[from=ellipse]{south west}
\inheritanchor[from=ellipse]{east}
\inheritanchor[from=ellipse]{mid east}
\inheritanchor[from=ellipse]{base east}
\inheritanchor[from=ellipse]{north east}
\inheritanchor[from=ellipse]{south east}
\inheritbackgroundpath[from=ellipse]
}
\makeatother
\begin{document}
\begin{tikzpicture}[
every node/.style={draw},
every newellipse node/.style={inner sep=0pt}
]
\path node (a) {A} -- ++(2cm,0)
node (b) {B};
\node[fit=(a)(b), newellipse] {};
\node[fit=(a)(b), red, newellipse, ellipse ratio=2] {};
\node[fit=(a)(b), blue, newellipse, ellipse ratio=6] {};
\end{tikzpicture}
\end{document}
Here's my original, somewhat more pragmatic answer:
You can adjust the inner xsep
and inner ysep
of the large ellipse independently, or use xscale
and yscale
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit,shapes.geometric}
\begin{document}
\begin{tikzpicture}[
every node/.style={inner sep=1pt},
proc/.style={shape=ellipse, draw}
]
\path node[proc] (q) {q} -- ++(2cm,0)
node[proc] (p1) {p$_1$} -- ++(1.5cm,0)
node (d) {\ldots} -- ++(1.5cm,0)
node[proc] (pn) {p$_n$};
\node[fit=(q)(p1)(d)(pn), proc, inner xsep=-3ex,inner ysep=2ex] {};
\node[fit=(q)(p1)(d)(pn), proc, red, xscale=0.75,yscale=2.5] {};
\end{tikzpicture}
\end{document}
My original answer is below the line. Here's a slightly improved version, which uses two "strategically-placed" pegs to distort the ellipse. I think this approach will need less manual fine tuning (of envel/inner sep
and peg/node distance
).
\begin{tikzpicture}[
every node/.style={inner sep=1pt},
proc/.style={shape=ellipse, draw},
peg/.style={draw=none,color=black!0,node distance=1cm},
envel/.style={shape=ellipse, draw, inner sep=-0.5cm}
]
\path node[proc] (q) {q} -- ++(2cm,0)
node[proc] (p1) {p$_1$} -- ++(1.5cm,0)
node (d) {\ldots} -- ++(1.5cm,0)
node[proc] (pn) {p$_n$};
\node [peg,above of=p1] (c1) {+};
\node [peg,below of=d] (c2) {+};
\node[fit=(q)(p1)(d)(pn)(c1)(c2), envel] {};
\end{tikzpicture}
Here's a slightly exaggerated answer. I suggest you play with the envel
construction's inner sep
and minimum height
parameters to find what suits you best.
\begin{tikzpicture}[
every node/.style={inner sep=1pt},
proc/.style={shape=ellipse, draw},
envel/.style={shape=ellipse, draw, inner sep=-0.5cm, minimum height=4.5cm}
]
\path node[proc] (q) {q} -- ++(2cm,0)
node[proc] (p1) {p$_1$} -- ++(1.5cm,0)
node (d) {\ldots} -- ++(1.5cm,0)
node[proc] (pn) {p$_n$};
\node[fit=(q)(p1)(d)(pn), envel] {};
\end{tikzpicture}
A PSTricks solution with the following macro syntex:
\Ellipse(<x_centre>,<y_centre>)(<width>,<height>){<label>}
Here is the code:
\documentclass{article}
\usepackage{pstricks}
\def\Ellipse(#1,#2)(#3,#4)#5{\psellipse(#1,#2)(#3,#4)\rput(#1,#2){#5}}
\begin{document}
\begin{pspicture}(8,2)
\psellipse(4,1)(4,1)
\Ellipse(1,1)(0.5,0.3){$p_{1}$}
\Ellipse(3,1)(0.5,0.3){$p_{2}$}
\Ellipse(5,1)(0.5,0.3){$\dots$}
\Ellipse(7,1)(0.5,0.3){$p_{n}$}
\end{pspicture}
\end{document}