2

I am trying to draw a depiction of a map that sends $1\mapsto 1/2$, $1/2\mapsto 1/3$, $1/3\mapsto 1/4$, etc.

The code I have is given as follows:

% page setup
\documentclass[11pt]{article}
\usepackage[a4paper, total={6in, 8in}]{geometry}

% basic packages
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{amssymb}
\usepackage{mathtools}
\usepackage{color}
\usepackage{titlesec}
\usepackage{enumitem}
\usepackage{changepage}
\usepackage[makeroom]{cancel}

% tikz
\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{calc}

% main document
\begin{document}

\begin{center}
    \begin{tikzpicture}[scale=5]
        % Draw the real line and the interval (0, 1]
        \draw[->] (-0.5, 0) -- (1.5, 0);
        \node at (0, 0) {$($};
        \node at (0, -0.08) {$0$};
        \node at (1, 0) {$]$};
        \node at (1, -0.08) {$1$};
        
        % Draw the points and arrows
        \filldraw (1, 0) circle (0.3pt);
        
        \foreach \x [evaluate=\x as \y using \x-1] [evaluate=\x as \z using (1/\x + 1/\y)/2] in {2, 3, 4, 5}
        {
            \filldraw (1/\x, 0) circle (0.3pt);
            \node at (1/\x, -0.08) {$\tfrac{1}{\x}$};
            
            \path[-] ($(1/\y, 0.06)-(0.00, 0)$) edge[out=90, in=0] ($(\z, 0.2)$);
            \path[->] ($(\z, 0.2)$) edge[out=180, in=90] ($(1/\x, 0.06)+(0.00, 0)$);
        }
        
        \node at (0.1, -0.08) {$\cdots$};
    \end{tikzpicture}
\end{center}

\end{document}

This gives me the image below.

enter image description here

My issue is, the last few arrows start to "pinch" outward and curve outward, which is undesirable for me. I think the drawing below demonstrates what I want and don't want.

enter image description here

Is there a way to make the arrows look like the ones on the left instead of the ones on the right? Any suggestions would be welcome.

Also, the reason I made each arrow path given by two lines

\path[-] ($(1/\y, 0.04)$) edge[out=90, in=0] ($(\z, 0.2)$);
\path[->] ($(\z, 0.2)$) edge[out=180, in=90] ($(1/\x, 0.04)$);

is because I want each arrow to reach the exact same height. This doesn't happen if I write a single line of code for each arrow. I'm not sure if this is good practice or not, but that is tertiary to main question.

2
  • Try and add some lower looseness depending on the distance between the ticks. And please, give a complete MWE, starting by \documentclass and ending by \end{document}.
    – SebGlav
    Commented Feb 12, 2023 at 20:28
  • Edited to give more complete code. Thanks for the suggestion. I'll look into it. Commented Feb 12, 2023 at 20:37

2 Answers 2

4

looseness adjustment

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\usepackage{amsmath}

\begin{document}


\begin{tikzpicture}[scale=5]
    % Draw the real line and the interval (0, 1]
    \draw[->] (-0.5, 0) -- (1.5, 0);
    \node at (0, 0) {$($};
    \node at (0, -0.08) {$0$};
    \node at (1, 0) {$]$};
    \node at (1, -0.08) {$1$};
    
    % Draw the points and arrows
    \filldraw (1, 0) circle (0.3pt);
    
    \foreach \x [evaluate=\x as \y using \x-1] [evaluate=\x as \z using (1/\x + 1/\y)/2] [count=\i from 0] in {2, 3, 4, 5}
    {
        \filldraw (1/\x, 0) circle (0.3pt);
        \node at (1/\x, -0.08) {$\frac{1}{\x}$};
        
        \path[-] ($(1/\y, 0.04)$) edge[out=90, in=0, looseness=1-0.15*\i] ($(\z, 0.2)$);
        \path[->] ($(\z, 0.2)$) edge[out=180, in=90, looseness=1-0.15*\i] ($(1/\x, 0.04)$);
    }
\end{tikzpicture}
\end{document}

Of course, this can be more precisely adjusted if you want.

2
  • Although I don't know why, but it doesn't accept expressions like looseness=1-0.15*\i and gives me errors Illegal unit of measure (pt inserted). } and Missing number, treated as zero. } This still happened even when I was in a test document where I copy+pasted your entire example. Commented Feb 12, 2023 at 20:59
  • 1
    I ended up instead replacing [count=\i from 0] with [evaluate=\x as \i using 1-0.15*(\x-2)] and looseness=1-0.15*\i with looseness=\i and it ended up working. Anyways, thank you so much! I really appreciate this. Commented Feb 12, 2023 at 20:59
3

I think you're doing it too complicated.

You can just use one path, here bend right = 90 which creates a curve that curves orthogonally (90°) to the line connecting start and target nodes/coordinates.

However, this isn't all that is needed, see

\tikz
  \foreach[count=\ii from 1] \i in {2,...,5}
    \draw (5/\ii,0) to[bend right=90] (5/\i,0);

enter image description here

Luckily, TikZ provides the distance key which changes the curve as you would like:

\tikz
  \foreach[count=\ii from 1] \i in {2,...,5}
    \draw (5/\ii,0) to[bend right=90, distance=1cm] (5/\i,0);

enter image description here


Unfortunately, PGF/TikZ will include the control points of these curves into the bounding box of the diagram adding a bit vertical whitespace on the top.

In this simple case, I'll make the path actually set to overlaybut I will place a coordinate at the middle which will be the highest point on these curves and will add this coordinate later to the bounding box.
This is not exactly the same because it ignores the line width but I don't think this is going to be a problem. You can always use the bbox library or take a look at related questions like Bounding box is larger than expected when drawing a curved path.


In your code, you just need to do

\draw[->] (1/\y, 0.06) to[bend right=90, distance=.2cm] (1/\x, 0.06);

to get the proper curves. (The 0.2cm will be scaled to 1cm the same your 0.2 did after it was converted to the canvas coordinate system.)


In my code below I'm mainly using the chains library with no placement rule (going {=}) since I want to place the dots manually at (1/\i, 0) but want to use the library's feature of connecting nodes on a chain. For this, the arr style is setup as mentioned above.

Alternative (for my code)

Instead of a Bézier curve you could also just draw an ellipsoid arc:

arr/.style={
  to path={
    (\tikztostart.north) arc [x radius={.5/(\i-1)-.5/(\i)},
                              y radius=.75,
                              start angle=0, delta angle=180]}}

which gives almost the same curves.

Alternative (for your code)

You could use the halfway point at the top but adjust the in distance and out distance respectivly.

However, since these can only be given in the canvas coordinate system (i.e. with units) but the distance between your dots is in the xyz coordinate system (without units) you would need to calculate that distance somehow or simply use the control points where you can specify the distance in the xyz coordinate system:

\draw[->] (1/\y, 0.06)
  to [controls=+(up:.1) and +(right:{.25*(1/\y-1/\x)})] (\z, 0.2)
  to [controls=+(left:{.25*(1/\y-1/\x)}) and +(up:.1)] (1/\x, 0.06);

Here the distance for the top point is a quarter of the distance between the dots, i.e. halfway between a dot and the top point.

Code

% page setup
%\documentclass[11pt]{article}
%\usepackage[a4paper, total={6in, 8in}]{geometry}
\documentclass[tikz, border=3mm]{standalone}
% tikz
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{chains}
% main document
\begin{document}
\begin{tikzpicture}[
  x=5cm, % better than scale
  start chain=going {=}, % no-op for placement
  label position=below,
  arr/.style={
    ->, bend right=90, distance=1cm,
    overlay, edge node=coordinate(@) % for bounding box fix
  }]
% Draw the real line and the interval (0, 1]
\draw[->] (-0.5, 0) -- (1.5, 0);
\node[label={[name=l-0]$0$}] at (0, 0) {$($}
 node[label=$1$]             at (1, 0) {$]$};

\scoped[disable label 1/.style=coordinate]
\foreach \i in {1, ..., 5}
  \node[% the dot
    circle, inner sep=+0pt, outer sep=+5pt,
    minimum size=+3pt, fill, draw,
    on chain, join=by arr] at (1/\i,0) {}
   node[% the fraction
    disable label \i/.try, % no label for 1/1
    anchor=base] (l-\i)
    at (l-0.base-|chain-end) {$\frac{1}{\i}$};
\path(@); % enlage bounding box

\node[base left, inner sep=+0pt] at (l-5.base west) {$\dots$};
\end{tikzpicture}
\tikz
  \foreach[count=\ii from 1] \i in {2,...,5}
    \draw (5/\ii,0) to[bend right=90] (5/\i,0);
    
\tikz
  \foreach[count=\ii from 1] \i in {2,...,5}
    \draw (5/\ii,0) to[bend right=90, distance=1cm] (5/\i,0);
\end{document}

Output

enter image description here

2
  • Of course, this is a better implementation. I just added some things to OP's code without reinvented it, but you did it well.
    – SebGlav
    Commented Feb 12, 2023 at 22:20
  • I'll definitely keep this in mind for future reference. Thank you. Commented Feb 12, 2023 at 22:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .