Turn tikz drawing into a macro

You can use a pic. The interface here isn't that good, but I think it works. To just add a black shape use e.g. \pic at (0,0) {randomblob};. As set up, randomblob has four key-value arguments, used as randomblob={<key>=<value>}. They are

  • edgecolor - the color of the line, black by default.
  • fillcolor - fill color. If not specified, no filling is done.
  • label - the text of a node placed in the center of the shape.
  • arrowtip - an arrow tip. If specified, 10 arrow tips are placed evenly along the path.

Other settings such as thick and fill opacity can be added to the pic, not randomblob.

enter image description here

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.markings,arrows.meta}
\pgfmathsetseed{\number\pdfrandomseed}

\tikzset{randomblob/.pic={
  \tikzset{%
    /randomblob/.cd,
    edgecolor=black,
    fillcolor=none,
    arrowtip={},
    label={},
    #1
}
% Set random in/out angles for the points
\pgfmathsetmacro{\a}{random(45,135)}
\pgfmathsetmacro{\b}{random(300,190)}
\pgfmathsetmacro{\c}{random(290,380)}
\pgfmathsetmacro{\d}{random(340,430)}
\pgfmathsetmacro{\e}{random(20,110)}
\pgfmathsetmacro{\f}{random(110,200)}
\pgfmathsetmacro{\g}{random(160,250)}
\pgfmathsetmacro{\h}{random(200,290)}

% Set random location for points.
% These points are based on an ellipse with horizontal radius 8 and vertical radius 6
\coordinate (a) at (8+1.5*rand,1.5*rand);
\coordinate (b) at (6+1.5*rand,4+1.5*rand);
\coordinate (c) at (1.5*rand,6+1.5*rand);
\coordinate (d) at (-6+1.5*rand,4+1.5*rand);
\coordinate (e) at (-8+1.5*rand,1.5*rand);
\coordinate (f) at (-6+1.5*rand,-4+1.5*rand);
\coordinate (g) at (1.5*rand,-6+1.5*rand);
\coordinate (h) at (6+1.5*rand,-4+1.5*rand);

\draw [
decoration={
markings,
mark=between positions 0 and 0.9 step 0.1 with {\arrow{\blobarrow}}
},
postaction={decorate},
fill=\blobfillclr,draw=\blobedgeclr]
      (a) to[out=\a,     in=\b]     (b)
          to[out=\b+180, in=\c]     (c)
          to[out=\c+180, in=\d]     (d)
          to[out=\d+180, in=\e]     (e)
          to[out=\e+180, in=\f]     (f)
          to[out=\f+180, in=\g]     (g)
          to[out=\g+180, in=\h]     (h)
          to[out=\h+180, in=\a+180] (a);

\node (0,0) {\bloblabel};

},
/randomblob/.search also={/tikz},
/randomblob/.cd,
label/.store in=\bloblabel,
edgecolor/.store in=\blobedgeclr,
fillcolor/.store in=\blobfillclr,
arrowtip/.store in=\blobarrow
}

\begin{document}
\begin{tikzpicture}[x=0.3cm,y=0.3cm]

\pic at (0,0) {randomblob={label=$a+b$,arrowtip={Stealth}}};
\pic [fill opacity=0.2,very thick] at (5,-2) {randomblob={fillcolor=blue,edgecolor=red}};
\pic[thick,blue] at (-5,-5) {randomblob={label={What?},arrowtip=latex,edgecolor=brown}};

\end{tikzpicture}
\end{document}

(I looked rather hard at https://tex.stackexchange.com/a/281102/586 when writing that code. In other words, I used pretty much exactly the same, so thanks cfr.)

Original answer

At the moment it doesn't fulfill your bonus points though, will have to get back to you on that. (Probably wont have time during the day, but maybe I can figure something out during the afternoon/evening.)

\documentclass[tikz]{standalone}
\pgfmathsetseed{\number\pdfrandomseed}
\tikzset{randomblob/.pic={
% Set random in/out angles for the points
\pgfmathsetmacro{\a}{random(45,135)}
\pgfmathsetmacro{\b}{random(300,190)}
\pgfmathsetmacro{\c}{random(290,380)}
\pgfmathsetmacro{\d}{random(340,430)}
\pgfmathsetmacro{\e}{random(20,110)}
\pgfmathsetmacro{\f}{random(110,200)}
\pgfmathsetmacro{\g}{random(160,250)}
\pgfmathsetmacro{\h}{random(200,290)}

% Set random location for points.
% These points are based on an ellipse with horizontal radius 8 and vertical radius 6
\coordinate (a) at (8+1.5*rand,1.5*rand);
\coordinate (b) at (6+1.5*rand,4+1.5*rand);
\coordinate (c) at (1.5*rand,6+1.5*rand);
\coordinate (d) at (-6+1.5*rand,4+1.5*rand);
\coordinate (e) at (-8+1.5*rand,1.5*rand);
\coordinate (f) at (-6+1.5*rand,-4+1.5*rand);
\coordinate (g) at (1.5*rand,-6+1.5*rand);
\coordinate (h) at (6+1.5*rand,-4+1.5*rand);

% Draw the randomly generated closed shape.
\draw (a) to[out=\a,     in=\b]     (b)
          to[out=\b+180, in=\c]     (c)
          to[out=\c+180, in=\d]     (d)
          to[out=\d+180, in=\e]     (e)
          to[out=\e+180, in=\f]     (f)
          to[out=\f+180, in=\g]     (g)
          to[out=\g+180, in=\h]     (h)
          to[out=\h+180, in=\a+180] (a);
 }}
\begin{document}
\begin{tikzpicture}

\pic at (0,0) {randomblob};
\pic[blue] at (2,2) {randomblob};
\pic[thick,red] at (-2,-2) {randomblob};
\end{tikzpicture}
\end{document}

enter image description here


As others have mentioned the pic is a useful way to go. Note, that if the loop is drawn using individual paths then a fill is not possible. Conversely, if the loop was drawn as one path then it would not be possible to get arrows on the individual segments of the loop without redrawing individual segments, unless a decoration is used:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{decorations.pathreplacing,math}
\tikzset{pics/random loop/.style={code={
\tikzmath{%
  integer \a; coordinate \p;
  \a1 = random(45,135);  \a2 = random(300,190);
  \a3 = random(290,380); \a4 = random(340,430);
  \a5 = random(20,110);  \a6 = random(110,200);
  \a7 = random(160,250); \a8 = random(200,290);
  \p1 = (8+1.5*rand,1.5*rand);  \p2 = (6+1.5*rand,4+1.5*rand);
  \p3 = (1.5*rand,6+1.5*rand);  \p4 = (-6+1.5*rand,4+1.5*rand);
  \p5 = (-8+1.5*rand,1.5*rand); \p6 = (-6+1.5*rand,-4+1.5*rand);
  \p7 = (1.5*rand,-6+1.5*rand); \p8 = (6+1.5*rand,-4+1.5*rand);
}
\path [pic actions/.try, postaction={decoration={show path construction, 
  curveto code={\path [pic outline/.try] 
   (\tikzinputsegmentfirst) .. controls(\tikzinputsegmentsupporta)
   and (\tikzinputsegmentsupportb) .. (\tikzinputsegmentlast);
}}, decorate}] (\p1)
  \foreach \i [evaluate={\j=int(mod(\i, 8)+1);
    \u = \a\i + (\i > 1) * 180; \v = \a\j + (\i == 8) * 180;}] in {1,...,8}{
      to [out=\u, in=\v] (\p\j) } -- cycle;
}}}
\begin{document}
\begin{tikzpicture}
\foreach \c [count=\i] in {red, yellow, pink, green, orange, purple, blue}
  \pic [fill=\c!50, 
    pic outline/.style={draw=\c!75!black, line width=0.25cm, ->}] 
    at (360/7*\i:16) {random loop};
\end{tikzpicture}
\end{document}

enter image description here


Here's a Metapost alternative. I like the fact that in MP you can make a macro that returns a path that you can assign to a variable, and then pass it to other commands like draw, reverse, fill and apply transformations to it like shifted, rotated, etc.

enter image description here

prologues := 3;
outputtemplate := "%j%c.eps";

% Make a random ellipsoid with semiaxes a,b and r amount of randomness
vardef random_ellipse(expr a,b,r) = 
   save e; path e;
   e = fullcircle xscaled a yscaled b;
   for i=1 upto length e: 
       point i of e shifted (r*normaldeviate, r*normaldeviate) .. 
   endfor cycle
enddef;

% Draw n evenly-space arrows along path p
vardef draw_arrows_along(expr p, n) = 
  save a; a = arclength p / n;
  for i=1 upto n:
     drawarrow subpath (arctime (i-1)*a of p, arctime i*a of p) of p;
  endfor
enddef;

beginfig(1);

randomseed := 3142;

path e[];

e1 = random_ellipse(144,89,13);
e2 = random_ellipse(144,89,13) shifted (200, 0);
e3 = random_ellipse(144,89,13) shifted (200, 150);
e4 = random_ellipse(144,89,13) shifted (  0, 150);

draw e1;

drawoptions(withcolor .67 red);

draw_arrows_along(e2,13);

drawoptions(withcolor .4 green);

draw_arrows_along(reverse e3, 32);

drawoptions();

fill e4 withcolor .8[blue,white];
draw e4 withcolor .67 blue;

label("A", center e1);
label("B", center e2);
label("C", center e3);
label("D", center e4);

endfig;
end.