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 would like to draw this figure :
enter image description here
Hence, I resort to TikZ. But, it seems to be very difficult drawing arrows precisely in TikZ with the precise locations (x,y). I have achieved this:
enter image description here
Here is the MWE:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\filldraw[color=gray] (1,0) rectangle (10,5);
\draw[->, line width=2pt, color=red] (2,1) -- (3,1);
\draw[->, line width=2pt, color=red] (2,2) -- (3,2.5);
\draw[->, line width=2pt, color=red] (3,2) -- (30:3);
\end{tikzpicture}
\end{document} 

Now, my question is

How to generate arrows of random length (between 2cm and 3cm) and random inclination (if possible of random colors too like red, yellow, violet, etc.) without crossing in TikZ. Is there any function to generate Random Numbers

Note:

If not Tikz, pstricks or MetaPost will also do. For now, Asmptote will not work because there seems an error in the execution in my system.

share|improve this question
    
I appreciate you accepted my answer, but may suggest you to wait a little longer before accepting an answer? I am sure some other answers will show up. –  Gonzalo Medina May 22 at 15:16
    
@GonzaloMedina Can you please edit your answer as the picture in my question. The spacing between arrows is much less. How to improve that? –  subham soni May 22 at 15:24
1  
I am afraid I don't completely understand. What do you want to change? –  Gonzalo Medina May 22 at 15:25
    
Please see the figure "I want to draw this:". In that, the spacing between the arrows is much. How to achieve this spacing? –  subham soni May 22 at 15:27
    
I'll have to think about this. In my current answer the starting point for each arrow as well as the ending point are randomly chosen so, in its present form, it's not easy to control the spacing. –  Gonzalo Medina May 22 at 15:33

6 Answers 6

up vote 16 down vote accepted

Updated version (without crossing):

A possibility with random colors, widths, directions, lengths; the image was produced using

\RandArrow

\def\Columns{10}
\RandArrow[80]

enter image description here

The code:

\documentclass{article} 
\usepackage{tikz}
\usetikzlibrary{calc}

\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\def\maxArrow{30}
\def\Columns{6}

\newcommand\randomarrow{
  \pgfmathsetseed{\pdfuniformdeviate 10000000}
  \edef\R{\pdfuniformdeviate 255}
  \edef\G{\pdfuniformdeviate 255}
  \edef\B{\pdfuniformdeviate 255}
  \xdefinecolor{mycolor}{RGB}{\R,\G,\B}
  \tikz\draw[->,line width=2pt*rnd+1pt,color=mycolor] 
    (rnd,rnd) -- ++(rnd*360:rnd+0.2);
}
\newcommand\RandArrow[1][30]{%
  \def\maxArrow{#1}  
  \begin{tikzpicture}
  \foreach [count=\i] \val in {1,...,\maxArrow} 
  { 
    \path  
      let \n{row}={int(mod(\i -1, \Columns))}, 
            \n{col}={ int( ( \i - 1 ) / (-\Columns) ) } 
      in 
         (\n{row}, \n{col}) rectangle  +(1,1) 
         +(0.5, 0.5) node{\randomarrow};
  }
  \begin{pgfonlayer}{background}
  \draw[orange!70!black,line width=1pt,fill=yellow!15]
    (current bounding box.north west)
      rectangle
    (current bounding box.south east);
  \end{pgfonlayer}
  \end{tikzpicture}%
}

\begin{document}

\RandArrow

\def\Columns{10}
\RandArrow[80]

\end{document}

The idea to avoid crossing arrows is to have a grid and place each arrow in one of the squares of the grid.

  1. \maxArrows allows to specify the number of arrows (initially set to 30).

  2. \Columns controls the number of rows of the grid (initially set to 6).

  3. \randomarrow draws an arrow; the width, length, color and direction are chosen randomly using rnd; the length will only be (in the worst case) 0.2cm larger than the width of the square; this is to prevent arrows from having zero length.

  4. The main command is \RandArrow with an optional argument allowing to decide the number of arrows to be drawn; the default value is 30.

  5. As suggested by Paul Gaborit in his answer, \pgfmathsetseed{\pdfuniformdeviate 10000000} was used in the definition of \randomarrow to change the seed used by the pseudo-random generator at each compilation.

Introducing some randomness in the grid gives better results:

\documentclass{article} 
\usepackage{tikz}
\usetikzlibrary{calc}

\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\def\maxArrow{30}
\def\Columns{6}

\newcommand\randomarrow{
  \pgfmathsetseed{\pdfuniformdeviate 10000000}
  \edef\R{\pdfuniformdeviate 255}
  \edef\G{\pdfuniformdeviate 255}
  \edef\B{\pdfuniformdeviate 255}
  \xdefinecolor{mycolor}{RGB}{\R,\G,\B}
  \tikz\draw[->,line width=2pt*rnd+1pt,color=mycolor] 
    (rnd,rnd) -- ++(rnd*360:rnd+0.1);
}
\newcommand\RandArrow[1][30]{%
  \pgfmathsetseed{\pdfuniformdeviate 10000000}
  \def\maxArrow{#1}  
  \begin{tikzpicture}
  \foreach [count=\i] \val in {1,...,\maxArrow} 
  { 
    \path  
      let \n{row}={ int(mod(\i -1, \Columns))}, 
            \n{col}={ int( ( \i - 1 ) / (-\Columns) ) } 
      in 
         (\n{row}, \n{col}) rectangle  +({random(2,3)},rand) 
         node[near start] {\randomarrow};
  }
  \begin{pgfonlayer}{background}
  \draw[orange!70!black,line width=1pt,fill=yellow!15]
    (current bounding box.north west)
      rectangle
    (current bounding box.south east);
  \end{pgfonlayer}
  \end{tikzpicture}%
}

\begin{document}

\RandArrow

\def\Columns{10}
\RandArrow[80]

\end{document}

enter image description here

share|improve this answer
1  
Just to be sure. Is there any difference between using \pgfmathparse{random()} \pgfmathsetmacro\xpos{\width*\pgfmathresult} or just \width*rnd instead of \xpos? –  Ignasi May 22 at 15:39
    
@Ignasi since I didn't use any arguments to random(), they should be equivalent. –  Gonzalo Medina May 22 at 15:43
    
@Ignasi now I edited my answer using arguments for some of the random and now rnd and random(2,3) behave differently. –  Gonzalo Medina May 22 at 15:58
    
Gonzalo I wanted to be sure because I didn't understand why was so much typping needed ;-) –  Ignasi May 22 at 16:25
    
Please see the edited question @GonzaloMedina –  subham soni May 22 at 16:25

Edit: random non crossing arrows

Here is a very simple solution (using a grid placement) with random colors, random lengths and random directions.

enter image description here

\documentclass[tikz]{standalone}
\pgfmathsetseed{\pdfuniformdeviate 10000000}
\begin{document}
\begin{tikzpicture}
  \fill[black] (0.5,0.5) rectangle (10.5,10.5);
  \foreach \x in {1,...,10} {
    \foreach \y in {1,...,10} {
      % random HSB color definition
      \pgfmathsetmacro\hue{rnd}
      \definecolor{mycolor}{rgb:hsb}{\hue,1,1}
      % random direction and length
      \pgfmathsetmacro\angle{rnd*360}
      \pgfmathsetmacro\halflen{rnd*.3+0.2}
      % arrow
      \draw[line width=2pt,-stealth,color=mycolor]
        (\x,\y) +(\angle:-\halflen) -- +(\angle:\halflen);
    }
  }
\end{tikzpicture}
\end{document} 

First version: random arrows

Here is a possible solution.

The rnd function generates a pseudo-random number between 0 and 1. Thus:

  • (rnd*4+3,rnd*4+3) gives a random coordinate between (3,3) and (7,7).
  • ++(rnd*360:rnd*2+1) moves the previous coordinate in any direction (rnd*360) with a length between 1cm and 3cm.

The random function used with two arguments x and y generates a random integer between x and y. Thus:

  • \pgfmathtruncatemacro\numcolor{random(0,3)} sets \numcolor with a random integer between 0 and 3.

To change the seed used by pseudo-random generator at each compilation, you may use (with pdflatex) \pgfmathsetseed{\pdfuniformdeviate 10000000} in your peamble.

enter image description here

\documentclass[tikz]{standalone}
\pgfmathsetseed{\pdfuniformdeviate 10000000}
\tikzset{
  my arrow/.style={-latex,line width=2},
  my arrow 0/.style={my arrow,color=red},
  my arrow 1/.style={my arrow,color=violet},
  my arrow 2/.style={my arrow,color=yellow},
  my arrow 3/.style={my arrow,color=black},
}
\begin{document}
\begin{tikzpicture}
  \filldraw[color=gray!50] (0,0) rectangle (10,10);
  \foreach \num in {1,...,20} {
    \pgfmathtruncatemacro\numcolor{random(0,3)}
    \draw[my arrow \numcolor] (rnd*4+3,rnd*4+3) -- ++(rnd*360:rnd*2+1);
  }
\end{tikzpicture}
\end{document} 
share|improve this answer

Random and not grid-aligned arrows, using the code from tikz: Distribute evenly and randomly circles:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\def\xlist{4}
\def\ylist{4}

\newcommand{\fillrandomly}[4]{
    \pgfmathsetmacro\diameter{#3*2}
    \draw (0-#3,0-#3) rectangle (#1+#3,#2+#3);
    \foreach \i in {1,...,#4}{
        \pgfmathsetmacro\x{rnd*#1}
        \pgfmathsetmacro\y{rnd*#2}
        \xdef\collision{0}
        \foreach \element [count=\i] in \xlist{
            \pgfmathtruncatemacro\j{\i-1}
            \pgfmathsetmacro\checkdistance{ sqrt( ({\xlist}[\j]-(\x))^2 + ({\ylist}[\j]-(\y))^2 ) }
            \ifdim\checkdistance pt<\diameter pt
                \xdef\collision{1}
                \breakforeach
            \fi
        }
        \ifnum\collision=0
            \xdef\xlist{\xlist,\x}
            \xdef\ylist{\ylist,\y}
            \pgfmathsetmacro\randomvalue{rnd*360}
            \draw [red, line width=4pt, -latex] (\x,\y) +(\randomvalue:-#3) -- +(\randomvalue:#3);
        \fi 

    }
}

\begin{tikzpicture}
\pgfmathsetseed{2}
\fillrandomly{7.5}{5}{0.5}{100}

\end{tikzpicture}
\end{document}
share|improve this answer
    
Where is the random length? :-) –  Who is crazy first May 22 at 19:01
    
@MoneyOrientedProgrammer: Adding random length, thickness, colour, arrowhead, curvature, etc. is trivial, so it does not need to be explicitly stated in the answer. –  Jake May 22 at 19:03
    
Confirmed. Thanks. –  Who is crazy first May 22 at 20:19
    
+1 for not using a grid. Way more randomish :-) –  Daniel May 23 at 5:35
\documentclass{article}

\usepackage{pstricks-add,multido}
\begin{document}

\begin{pspicture}(-6,-6)(6,6)
\pstVerb{ realtime srand }% For different output of every run
\psframe[linecolor=black!15](-5,-5)(5,5)
\multido{\iRow=-4+1}{9}{%
  \multido{\iCol=-4+1}{9}{%
    \rput{!Rand 360 mul}(\iRow,\iCol){%
      \pscustom{%
        \arrows{->}
        \code{Rand Rand Rand setrgbcolor 
           0 Rand 32 mul dup neg 0 exch ArrowB moveto 
           lineto Rand 2 mul setlinewidth stroke}}}}}
\end{pspicture}
\end{document} 

enter image description here

share|improve this answer
    
Please see the edited question @Herbert –  subham soni May 22 at 16:26

A try with MetaPost, using its handy uniformdeviate() random function, which generates a random number between 0 and the number specified in argument. The generated vectors are of random-generated origin, direction and length (between 2 cm and 3 cm), they can't be too close to each other thanks to a bb macro which puts a given vector into a "bounding box" and checks with the intersectiontimes function if they don't intersect, and they are of random colors in the RGB specification.

u := 1cm; % unit length
nb_vectors := 20; wd = .5; 
boolean intersect; pair random_origin; color random_color; path candidate, random_vector[], bb_candidate, bb[];
%
vardef bb(expr p) =
  save orig, extr; pair orig, extr; orig = point 0 of p; extr = point 1 of p;
  pair v,w; v = wd*unitvector(extr-orig)*u; w = v rotated 90;
  (orig - v + w) -- (extr + v + w) -- (extr + v - w) -- (orig - v - w) -- cycle
enddef;
%
beginfig(1);
  pickup pencircle scaled 2bp;
  i = 1; 
  forever: 
    exitunless (i <=  nb_vectors);
    intersect := false;
    random_length := u*(2+uniformdeviate(1));
    random_angle := uniformdeviate(359);
    random_origin := u*(uniformdeviate(wd*nb_vectors), uniformdeviate(wd*nb_vectors));
    random_color := (uniformdeviate(1), uniformdeviate(1), uniformdeviate(1));
    candidate := random_origin -- (random_origin + random_length*dir(random_angle));
    j := 1;
    forever:
      exitif (j = i) or (intersect = true);
      if bb(random_vector[j]) intersectiontimes bb(candidate) <>  (-1, -1):
        intersect := true;
      fi;
      j := j+1;
    endfor;
    if intersect = false: 
      random_vector[i] = candidate;
      drawarrow candidate withcolor random_color;
      i := i+1;
    fi;
  endfor;
endfig;
end.

Here one of the possible result:

enter image description here

share|improve this answer

Modifying the existing PSTricks answer to be more compact, perhaps!

\documentclass[pstricks,border=12pt]{standalone}   

\pstVerb
{
  realtime srand
  /setRGBcolor /setrgbcolor load def
  /setgray { pop tx@Dict begin Rand Rand Rand end setRGBcolor } def
  /Get {8 Rand mul 4 sub} bind def
}

\begin{document}
\begin{pspicture}[arrows=->](-4,-4)(4,4)
\psframe*[linecolor=black!15](-4,-4)(4,4)
\psLoop{100}{\psline(!Get Get)(!Get Get)}
\end{pspicture}
\end{document}

enter image description here

Animated version

\documentclass[pstricks,border=12pt]{standalone}   

\pstVerb
{
  realtime srand
  /setRGBcolor /setrgbcolor load def
  /setgray { pop tx@Dict begin Rand Rand Rand end setRGBcolor } def
    /Get {8 Rand mul 4 sub} bind def
}

\begin{document}
\psLoop{25}{%
\begin{pspicture}[arrows=->,linewidth=2pt](-4,-4)(4,4)
\psframe*[linecolor=black!15](-4,-4)(4,4)
\psLoop{25}{\psline(!Get Get)(!Get Get)}
\end{pspicture}}
\end{document}

enter image description here

share|improve this answer
    
Epilepsy warning! –  Who is crazy first May 22 at 16:15
    
Please see my edited question –  subham soni May 22 at 16:27
    
@MoneyOrientedProgrammer: How can you stop the arrows from crossing? –  Jake May 22 at 19:04
1  
@Jake: By increasing the frame rate so nobody can see they are actually crossing one over others. :-) –  Who is crazy first May 22 at 19:08

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.