Tutorial 6: Generating Networks

Sometimes you don’t want real data at all — you want a network with known, controllable properties, to teach a concept, test a method, or run a simulation against. nwcommands ships four generators, each producing a different, well-studied kind of structure, and nwrandom can also draw a random network in which every node has a degree you choose.

Random networks (Erdős–Rényi)

nwrandom gives every potential tie the same, independent probability of existing:

. nwclear

. nwrandom 15, prob(.2) undirected

. nwsummarize
--------------------------------------------------
   Network name:  random
   Network id:  1
   Directed: false
   Valued: false
   Two-mode: false
   Nodes: 15
   Selfloop: false
   Edges: 22
   Minimum value:  0
   Maximum value:  1
   Density:  .21
   Temporal: false

prob() leaves the exact tie count to chance — .21 density here, not exactly .2. Use density() instead to fix the tie count exactly:

. nwrandom 15, density(.2) undirected name(randdens)

. nwsummarize randdens
--------------------------------------------------
   Network name:  randdens
   Network id:  2
   Directed: false
   Valued: false
   Two-mode: false
   Nodes: 15
   Selfloop: false
   Edges: 21
   Minimum value:  0
   Maximum value:  1
   Density:  .2
   Temporal: false

weights() assigns a value to each placed tie, independent of how the tie itself was placed — here, weight 1 never occurs (probability 0.0), weight 2 occurs about 30% of the time, and weight 3 about 70%:

. nwrandom 15, prob(.2) undirected weights(0.0, 0.3, 0.7) name(randval)

. nwsummarize randval
--------------------------------------------------
   Network name:  randval
   Network id:  3
   Directed: false
   Valued: true
   Two-mode: false
   Nodes: 15
   Selfloop: false
   Edges: 19
   Minimum value:  0
   Maximum value:  3
   Density:  .181
   Temporal: false

Small-world networks (Watts–Strogatz)

nwsmall starts from a ring lattice — every node tied to its k nearest neighbors on each side — then rewires a fraction of those ties at random. The result keeps the ring’s local clustering while a few long-range “shortcuts” dramatically shrink the distance between distant nodes — the classic “small-world” effect:

. nwsmall 20, k(2) prob(.1) undirected

. nwsummarize
--------------------------------------------------
   Network name:  small
   Network id:  4
   Directed: false
   Valued: false
   Two-mode: false
   Nodes: 20
   Selfloop: false
   Edges: 40
   Minimum value:  0
   Maximum value:  1
   Density:  .211
   Temporal: false

. nwplot, layout(circle) scheme(s1network) export("plot_smallworld.svg") replace

Small-world network on a circle layout

Laid out on a circle, most ties stay short (connecting near-neighbors on the ring), with a handful of longer chords cutting across — those are the rewired shortcuts.

Preferential attachment (Barabási–Albert)

nwpref grows a network one node at a time: each new node is more likely to connect to already-well-connected nodes than to obscure ones. This “rich get richer” dynamic produces a characteristic hub structure — a few nodes accumulate far more ties than the rest:

. nwpref 20, undirected

. nwsummarize
--------------------------------------------------
   Network name:  pref
   Network id:  5
   Directed: false
   Valued: false
   Two-mode: false
   Nodes: 20
   Selfloop: false
   Edges: 37
   Minimum value:  0
   Maximum value:  1
   Density:  .195
   Temporal: false

. nwdegree, generate(deg)
----------------------------------------
  Network name: pref
----------------------------------------
    Degree distribution

        deg |      Freq.     Percent        Cum.
------------+-----------------------------------
          2 |         11       55.00       55.00
          3 |          2       10.00       65.00
          5 |          3       15.00       80.00
          6 |          1        5.00       85.00
          7 |          2       10.00       95.00
         11 |          1        5.00      100.00
------------+-----------------------------------
      Total |         20      100.00

   Degree centralization: .427

. sort deg _nwnode

. list _nwnode deg in -5/-1

     +---------------+
     | _nwnode   deg |
     |---------------|
 16. |      n8     5 |
 17. |      n3     6 |
 18. |      n2     7 |
 19. |      n4     7 |
 20. |      n1    11 |
     +---------------+

Over half the nodes have only degree 2, while n1 — one of the earliest nodes, and so one of the first eligible targets for every later arrival — ends up with degree 11. Sizing nodes by degree makes the hub visible directly:

. nwplot, layout(circle) scheme(s1network) size(deg) export("plot_prefattach.svg") replace

Preferential-attachment network with node size proportional to degree

Lattice networks

nwlattice generates a plain structured grid — no randomness at all — useful as a baseline or for teaching (e.g. contrasting a regular structure against the random/small-world/preferential ones above). xwrap/ywrap wrap the grid’s edges around so every node has exactly 4 neighbors:

. nwlattice 4 4, xwrap ywrap

. nwsummarize
--------------------------------------------------
   Network name:  lattice
   Network id:  6
   Directed: true
   Valued: false
   Two-mode: false
   Nodes: 16
   Selfloop: false
   Arcs: 64
   Minimum value:  0
   Maximum value:  1
   Density:  .267
   Temporal: false

. nwplot, layout(grid) label(_nwnode) scheme(s1network) export("plot_lattice.svg") replace

4x4 wrapped lattice network on a grid layout

Random networks with given degrees

Real networks rarely have the degrees of an Erdős–Rényi network: a few nodes have many ties and many have few. nwrandom with degree() draws a network in which every node has exactly the degree you give and the ties are otherwise random (no loops, no pair tied twice). It first builds one network with these degrees and then exchanges the partners of two ties at random many times (the sample_degseq(method = "edge.switching.simple") of igraph). degree() takes a list of numbers or a variable:

. set seed 2026

. nwrandom 8, degree(3 3 2 2 2 2 1 1) name(randdeg)

. nwdegree randdeg, generate(d_randdeg)
----------------------------------------
  Network name: randdeg
----------------------------------------
    Degree distribution

  d_randdeg |      Freq.     Percent        Cum.
------------+-----------------------------------
          1 |          2       25.00       25.00
          2 |          4       50.00       75.00
          3 |          2       25.00      100.00
------------+-----------------------------------
      Total |          8      100.00

   Degree centralization: .19

. list _nwnode d_randdeg in 1/8, noobs

  +--------------------+
  | _nwnode   d_rand~g |
  |--------------------|
  |      n1          3 |
  |      n2          3 |
  |      n3          2 |
  |      n4          2 |
  |      n5          2 |
  |--------------------|
  |      n6          2 |
  |      n7          1 |
  |      n8          1 |
  +--------------------+

Not every list of degrees can be the degrees of a network. Three nodes with one tie each would need one and a half ties, and nwrandom says so:

. capture noisily nwrandom 3, degree(1 1 1) name(bad)
No network without loops and repeated ties has these degrees (their sum must be even, and
> no degree can exceed 2; see the Erdos-Gallai conditions).
invalid syntax

The most useful degrees are those of a real network. Random networks with the degrees of the Florentine marriage network show what the degrees alone produce. The global clustering coefficient of the families is .19; the random network with their degrees has .13:

. nwwebuse florentine, nwclear

. nwdegree flomarriage, generate(d_flo)

. nwrandom 16, degree(d_flo) name(floran) xvars

. nwclustering flomarriage, generate(cc1) replace
----------------------------------------
  Network name: flomarriage
----------------------------------------
    Measure: binary
    Average clustering coefficient: .218
    Global clustering coefficient: .191

. nwclustering floran, generate(cc2) replace
----------------------------------------
  Network name: floran
----------------------------------------
    Measure: binary
    Average clustering coefficient: .118
    Global clustering coefficient: .128

One random network proves little. Many of them, compared with the observed value, make a test: nwcug with condition(degrees) does exactly that (Tutorial 18). For a directed network give outdegree() and indegree() (for example the variables of nwdegree); every node then keeps both. To rewire an observed network instead of starting from a list, use nwpermute with swap (nwpermute), which also carries tie values along.


Back to top

nwcommands is free software under the GNU General Public License, version 3, as are the model packages nwsaom, nwergm, nwdynam and nwrem. Citing and licenses · Get help · GitHub. Issues with the core go to the nwcommands repository; issues with a model package go to that package's own repository.

This site uses Just the Docs, a documentation theme for Jekyll.