The answer Torbjørn points in the comments is related, but the circles there have always the same radius.
Another approach:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fadings,shapes.arrows,shadows}
\usepackage{xparse}
\tikzfading[name=arrowfading, top color=transparent!0, bottom color=transparent!95]
\tikzset{arrowfill/.style={#1,general shadow={fill=black, shadow yshift=-0.8ex, path fading=arrowfading}}}
\tikzset{arrowstyle/.style n args={3}{draw=#2,arrowfill={#3}, single arrow,minimum height=#1, single arrow,
single arrow head extend=.3cm,}}
\NewDocumentCommand{\tikzfancyarrow}{O{2cm} O{FireBrick} O{top color=OrangeRed!20, bottom color=Red} m}{
\tikz[baseline=-0.5ex]\node [arrowstyle={#1}{#2}{#3}] {#4};
}
% Parameters
\def\height{5}
\def\width{10}
\def\numpoints{500}
\def\maxpointwidth{1.75}
\begin{document}
\begin{tikzpicture}
\path (0,0) rectangle (\width,\height);
\foreach \point in {1,...,\numpoints}{
\pgfmathparse{random()}
\pgfmathsetmacro\xpos{\width*\pgfmathresult}
\pgfmathparse{random()}
\pgfmathsetmacro\ypos{\height*\pgfmathresult}
\pgfmathrandom{0.1,\maxpointwidth}
\let\pointwidth\pgfmathresult
\node[circle,inner sep=\pointwidth pt,fill=blue!30] (point-\point) at (\xpos,\ypos) {};
}
\node [arrowstyle={\height cm}{black}{top color=orange,bottom color=yellow,shape border rotate=270}] at (\width/2,\height/2) {};
\end{tikzpicture}
\end{document}
![enter image description here](https://i.stack.imgur.com/fGU9C.png)
This uses Fancy arrows with TikZ to create the gradient and the various parameters could be set in the preamble.
This could be probably an overkilling solution, but allows to achieve an higher customization:
\documentclass[tikz,png]{standalone}
\usepackage{tikz}
\usetikzlibrary{fadings,shapes.arrows,shadows}
\usepackage{xparse}
\newif\ifshadecircle
\pgfkeys{/tikz/.cd,
height rect/.initial=5,
height rect/.get=\height,
height rect/.store in=\height,
width rect/.initial=10,
width rect/.get=\width,
width rect/.store in=\width,
num points/.initial=500,
num points/.get=\numpoints,
num points/.store in=\numpoints,
point width/.initial=1.5pt,
point width/.get=\maxpointwidth,
point width/.store in=\maxpointwidth,
point style type/.is choice,
point style type/fill/.style={fill=\pointcolor},
point style type/radial shade/.style={inner color=\pointinnercolor,outer color=\pointoutercolor},
point style type/vertical shade/.style={top color=\pointtopcolor,bottom color=\pointbottomcolor},
point style type/horizontal shade/.style={left color=\pointleftcolor,right color=\pointrightcolor},
point style/.initial={/tikz/point style type/fill},
point style/.get=\pointstyle,
point style/.store in=\pointstyle,
point fill color/.initial=blue!30,
point fill color/.get=\pointcolor,
point fill color/.store in=\pointcolor,
point inner color/.initial=white,
point inner color/.get=\pointinnercolor,
point inner color/.store in=\pointinnercolor,
point outer color/.initial=blue!30,
point outer color/.get=\pointoutercolor,
point outer color/.store in=\pointoutercolor,
point top color/.initial=white,
point top color/.get=\pointtopcolor,
point top color/.store in=\pointtopcolor,
point bottom color/.initial=blue!30,
point bottom color/.get=\pointbottomcolor,
point bottom color/.store in=\pointbottomcolor,
point left color/.initial=blue!30,
point left color/.get=\pointleftcolor,
point left color/.store in=\pointleftcolor,
point right color/.initial=white,
point right color/.get=\pointrightcolor,
point right color/.store in=\pointrightcolor,
arrow top color/.initial=orange,
arrow top color/.get=\arrowtopcolor,
arrow top color/.store in=\arrowtopcolor,
arrow bottom color/.initial=yellow,
arrow bottom color/.get=\arrowbottomcolor,
arrow bottom color/.store in=\arrowbottomcolor,
arrow border color/.initial=black,
arrow border color/.get=\arrowbordercolor,
arrow border color/.store in=\arrowbordercolor,
}
\tikzfading[name=arrowfading, top color=transparent!0, bottom color=transparent!95]
\tikzset{arrowfill/.style={#1,general shadow={fill=black, shadow yshift=-0.8ex, path fading=arrowfading}}}
\tikzset{arrowstyle/.style n args={3}{draw=#2,arrowfill={#3}, single arrow,minimum height=#1, single arrow,
single arrow head extend=.15cm,}}
\pgfkeys{/tikz/random point diagram/.code={
\path (0,0) rectangle (\width,\height);
\foreach \point in {1,...,\numpoints}{
\pgfmathparse{random()}
\pgfmathsetmacro\xpos{\width*\pgfmathresult}
\pgfmathparse{random()}
\pgfmathsetmacro\ypos{\height*\pgfmathresult}
\pgfmathparse{random()}
\pgfmathsetmacro\pointwidth{\maxpointwidth*\pgfmathresult}
\node[circle,inner sep=\pointwidth pt, \pointstyle] (point-\point) at (\xpos,\ypos) {};
}
\node [arrowstyle={\height cm}{\arrowbordercolor}{top color=\arrowtopcolor, bottom color=\arrowbottomcolor,shape border rotate=270}, anchor=north] at (\width/2,\height) {};
}
}
% that's just an alias for \node
\makeatletter
\def\drawdiagram{\tikz@path@overlay{node}}
\makeatother
\begin{document}
\begin{tikzpicture}
\drawdiagram[random point diagram] at (0,0) {};
\end{tikzpicture}
\begin{tikzpicture}[height rect=4,width rect=8,
num points=600,
point style={/tikz/point style type/vertical shade},
point top color=white,
point bottom color=orange,
arrow border color=violet,
arrow top color=violet!50!magenta!80,
arrow bottom color=magenta!20]
\drawdiagram[random point diagram] at (0,0) {};
\end{tikzpicture}
\end{document}
The first example with the default values gives the previous picture, while the second customized example:
![enter image description here](https://i.stack.imgur.com/gydgd.png)
To change a pattern it is necessary to first understand all the macros involved. What happens with
\pgfpathcircle{\pgfqpoint{0pt}{0pt}}{.5pt}
\pgfpathcircle{\pgfqpoint{1.5pt}{1.5pt}}{.5pt}
\pgfusepath{fill}
is that you draw two circles of radius .5pt
one at coordinates (0pt,0pt) and the other at (1.5pt,1.5pt) and you repeat them along a path. The pattern is composed of several paths of course. Imagine to have a square, where the bottom left angle is at (-1pt,-1pt)
and the top right at (2.5pt,2.5pt)
. To create the pattern, you fill with dots a path from the left angle to the right angle. Then you move right and repeat the procedure: now this path will be drawn from (-0.7pt, -1pt)
to (2.5pt,2.3pt)
say and keep repeating. This will fill the lower triangle of the square. The procedure is similar for the top triangle.
As you can imagine, if you want to reduce the number of dots you can: a) increase the distance between the two dots, b) increase the distance between the pair of two dots in the pattern, c) a combination of the two.
In the following, I show an example of method c:
\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{patterns}
\pgfdeclarepatternformonly{my crosshatch dots}{\pgfqpoint{-1pt}{-1pt}}{\pgfqpoint{5pt}{5pt}}{\pgfqpoint{6pt}{6pt}}%
{
\pgfpathcircle{\pgfqpoint{0pt}{0pt}}{.5pt}
\pgfpathcircle{\pgfqpoint{3pt}{3pt}}{.5pt}
\pgfusepath{fill}
}
\begin{document}
\begin{tikzpicture}
\draw[pattern=my crosshatch dots] (0,0) rectangle (2,2);
\end{tikzpicture}
\end{document}
The result:
![enter image description here](https://i.stack.imgur.com/r0pDT.png)
The best in this case would be to use the optional parameter of \pgfdeclarepatternformonly
and define a macro to control the distance. Beware: if you do so, you may want to change all \pgfqpoint
into \pgfpoint
.
Best Answer
As explained in a comment, the code for the pattern is evaluated only once, so you cannot have new random dots for each time the pattern is repeated, but the same random dots that were computed when the pattern was defined.
I suggested in a comment to define a "huge pattern" of the size of the page. However, after doing some tests, I discovered that this solution is not practical. In order to cover the page with a density of dots similar of the one in the image you posted, tens of thousands of dots should be generated, and the time is prohibitive. Even if this should be evaluated once, when the pattern is defined, and not later for each use of the pattern, the time will be excesive.
So here is another idea you can play with.
First, generate a pdf containing a "sparse" random pattern:
This takes less than 2sec to compile and produces the following
random-pattern.pdf
:Now, you can use this image as "basic stamp" that you can randomly place and rotate several times in your figure to create a more dense pattern:
This is the result (also compiled under 2sec):
Problems
Of course it would be nice to use this idea to generate a pattern. Unfortunately, patterns cannot contain external images.
The problem of the image not being a "true" pattern, is that the density of dots in the result is not uniform. In the center of the image there are more dots than in the borders. Even if the "stamp" is randomly and uniformly "stamped" in the 5x5 square, the "stamps" which fall near the borders contribute less to the final result than the ones which "fall" near the center. This problem can be understood if we remove the clipping:
If the image were useable inside a true pattern, we could define the "bounding box" of the pattern to be smaller than the image, and then the canvas would behave like a torus surface, in which the bits of the pattern that "fall off" to the right, "enter" again from the left, and vice-versa. This would produce a more uniform dotting. I was unable to imagine a solution for this problem.
Update
After reading OP's update to the question, I have to elaborate a bit my answer.
As explained by @MarkWibrow in a comment, a by me in the answer to another question, the pattern is not drawn at tikz/pgf level, but instead converted to the language used by the driver (PDF or PS), and passed as argument to the pattern-drawing primitives of those languages. This precludes the possibility of having that code evaluated every time that the pattern is needed.
One could think that a solution would be to write directly code in the backend language (via specials). This way, instead of using tikz's
rnd
function, one could use some PDF/PS native random function, in the hope that it would be evaluated every time the pattern is drawn. However this approach would fail for PDF, because it lacks proper programming constructs (it does not have random functions, nor ability to do loops).PostScript is a more complete language and it would be certainly possible to write a function which performs a loop to draw any number of dots at random coordinates, using pure PostScript code. However, I don't know the details of pattern definition in PostScript, so it is possible (depending on how patterns work in PS) that you hit the same problem than at tikz/pgf level, i.e: that the definition of the pattern is used once to compute an image which is later repeated where needed.
Update's update
My concerns in the last paragraph about the futility of trying a pure postscript implementation were confirmed by reading page 253 (267 in pdf) of the PostScript specification. The pattern is defined through several parameters, one of which is what the spec calls
PaintProc
, which is a function in pure PostScript which "draws" the content of the pattern tile. This code can contain any postscript, so it would be possible to use loops andrand
to get the random-dots pattern, but:So, in summary, it is not possible to have a pattern tile which is redered differently each time it is drawn.