# Ego Networks: Name Generators, Interpreters, Dyad Census and Sociograms

Source: https://www.potatoannotator.com/docs/annotation-types/ego-network

*New in v2.12.0*

`ego_network` collects a personal (egocentric) network, a standard object of [social network analysis](https://en.wikipedia.org/wiki/Social_network_analysis). The respondent, the ego, names people (alters), answers questions about each of them, says which of them know each other, and places them on a map. The scheme works on a survey page, which is how most personal-network studies run it, and on annotation items, where a coder records the network a document describes.

One scheme holds an ordered list of stages. Every stage works on the same set of alters, so a person named in the first name generator appears in every later stage.

| Stage | What the respondent does |
|---|---|
| `name_generator` | Types names in answer to a prompt, or picks them from a list |
| `name_interpreter` | Answers the same questions about each person (radio, multiselect, number, text) |
| `dyad_census` | Says, for every pair of people, whether they know each other: n(n-1)/2 pairs, one at a time, with a progress bar |
| `sociogram` | Drags people around a canvas and clicks two people to add or remove a line between them |

By default the stages are shown one at a time, each with its own Back and Next buttons and a row of step buttons. `stage_layout: stacked` shows them all on the page at once.

## Configuration

On a survey page, list the page under `phases` and put the scheme in its file:

```yaml
phases:
  order: [your_network, annotation]
  your_network:
    type: prestudy
    file: surveys/your-network.json
```

The page file holds the scheme, shown here in YAML. The same keys work in `annotation_schemes`:

```yaml
- annotation_type: ego_network
  name: personal_network
  description: People you talk to
  label_requirement:
    required: true
  stages:
    - type: name_generator
      id: discuss
      title: Important matters
      prompt: >-
        Looking back over the last six months, who are the people you talked
        to about matters that are important to you?
      min_alters: 1
      max_alters: 8
      sets: {discuss: true}
    - type: name_generator
      id: help
      title: Practical help
      prompt: Who would you ask for help if you were ill for a couple of weeks?
      sets: {help: true}
    - type: name_interpreter
      id: about
      title: About each person
      required: true
      questions:
        - name: closeness
          type: radio
          description: How close do you feel to {name}?
          labels:
            - {name: very, text: Very close}
            - {name: somewhat, text: Somewhat close}
            - {name: not, text: Not close}
        - name: years_known
          type: number
          description: About how many years have you known {name}?
          min: 0
          max: 100
          required: false
    - type: dyad_census
      id: know
      prompt: Do {a} and {b} know each other?
    - type: sociogram
      id: map
      rings: 3
```

| Option | Default | Meaning |
|---|---|---|
| `stages` | required | The stages, in order. A `name_generator` must come before any other stage |
| `stage_layout` | `steps` | `steps` shows one stage at a time, `stacked` shows them all at once |
| `label_requirement` | none | `{required: true}` stops the page from continuing until the network is complete |

Every stage takes `type`, `id` (a letter followed by letters, digits, `_` or `-`, defaulting to `<type>_<n>`), `title`, `prompt` and `instructions`.

### Name generators

| Option | Default | Meaning |
|---|---|---|
| `min_alters` | `0` | People this stage needs before the respondent can go on |
| `max_alters` | none | Most people this stage accepts |
| `roster` | none | Names to pick from instead of typing: strings, or `{id, name}` |
| `roster_field` | none | An item field holding the list (annotation items only) |
| `sets` | none | Attributes given to everyone named in this stage, such as `{support: true}` |
| `placeholder` | `First name or nickname` | Placeholder of the name box |

Typing a name already on the list is refused with a message, so one person is not recorded twice. A later name generator lists the people named earlier under "Named earlier", and the respondent adds anyone who also belongs there with one click. The alter keeps one ID and records every generator that named them. Removing a person from the only generator that named them removes them from the network, with their answers and ties.

### Name interpreters

A `name_interpreter` stage takes `questions` (required) and `required`, the default for its questions. Each question has `name` (unique across the scheme), `type` (`radio`, `multiselect`, `number` or `text`), `description` (`{name}` is replaced by the person's name), `labels` for radio and multiselect (strings or `{name, text}`, where `name` is what is stored), `required`, and `min`, `max` and `step` for numbers. The page shows one card per person with every question on it.

### Dyad census

| Option | Default | Meaning |
|---|---|---|
| `prompt` | `Do {a} and {b} know each other?` | `{a}` and `{b}` are replaced by the two names |
| `relation` | none | Name of the relation, when a study records more than one kind of tie |
| `yes_label`, `no_label` | `Yes`, `No` | Answer labels |
| `strength_labels` | none | Asks how strong the tie is instead of yes, with one button per label plus `no_label` |
| `strength_variable` | `strength` | Tie attribute the strength answer is stored under |

The census shows one pair at a time and moves to the next unanswered pair after each answer. "All pairs" lists every pair with its answer, and clicking one goes back to it.

### Sociogram

| Option | Default | Meaning |
|---|---|---|
| `relation` | none | The relation the lines record |
| `allow_ties` | `true` | `false` for a placement-only canvas |
| `rings` | `3` | Concentric circles drawn behind the people, from 0 to 6 |

Positions are saved as fractions of the canvas width and height. A line drawn on the sociogram and a census answer for the same relation are the same record, so drawing a line between two people sets their census answer to yes, and removing it sets it to no.

Every control is a button or a text box reachable with Tab. On the sociogram, Tab moves between people, Enter selects one and opens a list of everyone else to add or remove ties, arrow keys move the focused person (Shift moves further), and Escape closes the list.

## Data format

The answer is stored as one JSON string:

```json
{
  "alters": [{"id": "a1", "name": "Ann", "named_in": ["discuss", "help"]},
             {"id": "a2", "name": "Bob", "named_in": ["discuss"]}],
  "attributes": {"a1": {"discuss": true, "help": true, "closeness": "very"}},
  "ties": [["a1", "a2"]],
  "positions": {"a1": [0.42, 0.31], "a2": [0.7, 0.55]},
  "census": {"a1|a2": true},
  "tie_attributes": {}
}
```

Alter IDs are `a1`, `a2` and so on, in the order people were named, and a deleted ID is not reused. A tie is `[a, b]`, or `[a, b, relation]` when the stage names a relation.

## Export

```bash
python -m potato.export --config config.yaml --format ego_network --output out/
```

| File | Contents |
|---|---|
| `egos.csv` | One row per network: `network_size`, `n_ties`, `possible_ties`, `density`, `isolates`, `components`, `relations`, and `complete` with `incomplete_reason` checked against the scheme's own rules |
| `alters.csv` | One row per alter: `alter_id`, `named_in`, `x`, `y`, `degree`, and one `attr_<name>` column per attribute |
| `edges.csv` | One row per tie: `source_alter`, `target_alter`, `relation` (`tie` when unnamed), and `tie_<name>` columns such as `tie_strength` |
| `graphml/<user>__<item>.graphml` | One [GraphML](https://en.wikipedia.org/wiki/GraphML) file per network, with alters as nodes and ties as undirected edges |

The ego is not a node in these files. Density, components and degree are computed over alter-alter ties, and two people tied on two relations count as one connected pair.

### Alter names

The names respondents type identify people who have not agreed to take part in the study, so the `ego_network` export leaves them out and writes the pseudonymous IDs only. `--option export_names=true` includes them.

The names are still in the raw output (`annotation_output/`) and in the general exports (`csv`, `jsonl`), which write the stored JSON as it is. Ask respondents for first names or nicknames, and handle those files as identifiable data.

## Completeness

With `label_requirement: {required: true}`, the page will not continue while a name generator has fewer than `min_alters` people, a required name-interpreter question is unanswered for someone, or a dyad census has unanswered pairs, and it says which. Inside the widget, Next stays on a name generator until it has `min_alters` people, whether or not the scheme is required.

## Importing a Network Canvas protocol

`potato import -f network_canvas -i my-study.netcanvas -o my-study/` reads a [Network Canvas](https://networkcanvas.com/) protocol, either the `.netcanvas` file saved in Architect or a bare `protocol.json`. Ego forms become pages of ordinary questions, and the network stages for each node type become one `ego_network` question:

| Network Canvas | Potato |
|---|---|
| `EgoForm` | A survey page, with the introduction panel as a heading |
| `Information` (text items) | A `pure_display` page, with Markdown reduced to plain text |
| `NameGenerator`, `NameGeneratorQuickAdd` | `name_generator` stages, one per prompt |
| `NameGeneratorRoster` | `name_generator` with a `roster` read from the protocol's CSV or JSON asset |
| `additionalAttributes` on a prompt | `sets` on that name generator |
| Extra fields on the add-person form | A `name_interpreter` stage right after the name generator |
| `AlterForm` | `name_interpreter` |
| `OrdinalBin`, `CategoricalBin` | `name_interpreter` with one radio question per prompt |
| `DyadCensus`, `OneToManyDyadCensus` | `dyad_census`, with `relation` from the edge type |
| `TieStrengthCensus` | `dyad_census` with `strength_labels` from the edge variable's options |
| `Sociogram` | `sociogram`, with `concentricCircles` as `rings` |
| `minNodes`, `maxNodes` | `min_alters` (first prompt), `max_alters` (each prompt) |

Option values are kept as the stored answers, so exports carry the same codes as the protocol. Skip logic on ego variables becomes page `show_when`, and a skip to a `FinishSession` stage becomes `exit_when` on the page before, so a participant who declines consent leaves the study there. Protocols with translations import in English unless you pass `--survey-language`.

Some things change. All network stages for one node type share one page, placed where the first of them was, so a network stage that came after other pages comes before them, and the import warns about each one. Dragging people into bins becomes one choice per person, with the same stored values. Skip logic that tests node or edge data, `AlterEdgeForm`, `Narrative`, `Geospatial` and the pedigree stages, date pickers, media items and interviewer notes are listed in `IMPORT_REPORT.md` and not imported.

## Example

`examples/advanced/ego-network/` runs the scheme twice: as a survey page before the task, for the participant's own network, and as the annotation task, where coders record the network each interview excerpt describes.

```bash
python potato/flask_server.py start examples/advanced/ego-network/config.yaml -p 8000
```

Quote `"Yes"` and `"No"` in label lists, because YAML reads them unquoted as booleans, and write `stage_layout: stacked`, not `layout: stacked`, since `layout` is the grid-placement mapping every scheme accepts.

## Further Reading

- [Survey Import](/docs/tools/survey-import) - Network Canvas and six other questionnaire formats
- [Multi-Phase Workflows](/docs/features/surveyflow) - Survey pages before and after the task
- [Cultural Domain Analysis](/docs/guides/cultural-domain-analysis) - Free lists and triad tests for the same respondents

For implementation details, see the [source documentation](https://github.com/davidjurgens/potato/blob/master/docs/annotation-types/structured/ego_network.md).
