Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to draw a Tikz diagram, in which an ellipse contains a row of smaller ellipses. I tried doing so using the fitting library:

\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] {};
\end{tikzpicture}

The result is a long and narrow ellipse:

bad ellipse

I would prefer the surrounding ellipse to be shorter and taller, i.e., end closer to the q and pn nodes, and also have slightly more height. What is the right configuration for this?

share|improve this question
add comment

2 Answers

up vote 5 down vote accepted

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}
share|improve this answer
    
@Little Bobby Tables If an answer is good enough to accept, it's good enough to upvote... –  Seamus Aug 1 '11 at 11:54
    
@Seamus; @Little Bobby Tables: Thank you both... (:-) –  Brent.Longborough Aug 1 '11 at 11:56
add comment

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

new ellipse with scale ratio

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}

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.