diff --git a/python/example/gap_junctions.py b/python/example/gap_junctions.py
new file mode 100644
index 0000000000000000000000000000000000000000..6564f90fb13799a3275ee18c527cf9d8ef0e6b13
--- /dev/null
+++ b/python/example/gap_junctions.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+
+import arbor
+import pandas, seaborn
+import matplotlib.pyplot as plt
+
+# Construct chains of cells linked with gap junctions,
+# Chains are connected by synapses.
+# An event generator is attached to the first cell in the network.
+#
+# c --gj-- c --gj-- c --gj-- c --gj-- c
+#                                     |
+#                                    syn
+#                                     |
+# c --gj-- c --gj-- c --gj-- c --gj-- c
+#
+# The individual cells consist of a soma and one dendrite
+
+
+def make_cable_cell(gid):
+    
+    # Build a segment tree
+    tree = arbor.segment_tree()
+
+    # Soma with radius 5 μm and length 2 * radius = 10 μm, (tag = 1)
+    s = tree.append(arbor.mnpos, arbor.mpoint(-10, 0, 0, 5), arbor.mpoint(0, 0, 0, 5), tag=1)
+
+    # Single dendrite with radius 2 μm and length 40 μm, (tag = 2)
+    b = tree.append(s, arbor.mpoint(0, 0, 0, 2), arbor.mpoint(40, 0, 0, 2), tag=2)
+
+    # Label dictionary for cell components
+    labels = arbor.label_dict()
+    labels['soma'] = '(tag 1)'
+    labels['dend'] = '(tag 2)'
+
+    # Mark location for synapse site at midpoint of dendrite (branch 0 = soma + dendrite)
+    labels['synapse_site'] = '(location 0 0.6)'
+
+    # Gap junction site at connection point of soma and dendrite
+    labels['gj_site'] = '(location 0 0.2)'
+
+    # Label root of the tree
+    labels['root'] = '(root)'
+
+    # Paint dynamics onto the cell, hh on soma and passive properties on dendrite
+    decor = arbor.decor()
+    decor.paint('"soma"', arbor.density("hh"))
+    decor.paint('"dend"', arbor.density("pas"))
+
+    # Attach one synapse and gap junction each on their labeled sites
+    decor.place('"synapse_site"', arbor.synapse('expsyn'), 'syn')
+    decor.place('"gj_site"', arbor.junction('gj'), 'gj')
+
+    # Attach spike detector to cell root
+    decor.place('"root"', arbor.spike_detector(-10), 'detector')
+
+    cell = arbor.cable_cell(tree, labels, decor)
+
+    return cell
+
+# Create a recipe that generates connected chains of cells
+class chain_recipe(arbor.recipe):
+
+    def __init__(self, ncells_per_chain, nchains):
+        arbor.recipe.__init__(self)
+        self.nchains = nchains
+        self.ncells_per_chain = ncells_per_chain
+        self.props = arbor.neuron_cable_properties()
+        self.cat = arbor.default_catalogue()
+        self.props.register(self.cat)
+
+    def num_cells(self):
+        return self.ncells_per_chain * self.nchains
+
+    def cell_description(self, gid):
+        return make_cable_cell(gid)
+
+    def cell_kind(self, gid):
+        return arbor.cell_kind.cable
+
+    # Create synapse connection between last cell of one chain and first cell of following chain
+    def connections_on(self, gid):
+        if (gid == 0) or (gid % self.ncells_per_chain > 0):
+            return []
+        else:
+            src = gid-1
+            w   = 0.05
+            d   = 10
+            return [arbor.connection((src,'detector'), 'syn', w, d)]
+    
+    # Create gap junction connections between a cell within a chain and its neighbor(s)
+    def gap_junctions_on(self, gid):
+        conns = []
+
+        chain_begin = int(gid/self.ncells_per_chain) * self.ncells_per_chain
+        chain_end   = chain_begin + self.ncells_per_chain
+
+        next_cell = gid + 1
+        prev_cell = gid - 1
+
+        if next_cell < chain_end:
+            conns.append(arbor.gap_junction_connection((gid+1, 'gj'), 'gj', 0.015))
+        if prev_cell >= chain_begin:
+            conns.append(arbor.gap_junction_connection((gid-1, 'gj'), 'gj', 0.015))
+        
+        return conns
+
+    # Event generator at first cell
+    def event_generators(self, gid):
+        if gid==0:
+            sched = arbor.explicit_schedule([1])
+            weight = 0.1
+            return [arbor.event_generator('syn', weight, sched)]
+        return []
+
+    # Place a probe at the root of each cell
+    def probes(self, gid):
+        return [arbor.cable_probe_membrane_voltage('"root"')]
+
+    def global_properties(self, kind):
+        return self.props
+
+# Number of cells per chain
+ncells_per_chain = 5
+
+# Number of chains
+nchains = 3
+
+# Total number of cells
+ncells = nchains * ncells_per_chain
+
+#Instantiate recipe
+recipe = chain_recipe(ncells_per_chain, nchains)
+
+# Create a default execution context, domain decomposition and simulation
+context = arbor.context()
+decomp = arbor.partition_load_balance(recipe, context)
+sim = arbor.simulation(recipe, decomp, context)
+
+# Set spike generators to record
+sim.record(arbor.spike_recording.all)
+
+# Sampler
+handles = [sim.sample((gid, 0), arbor.regular_schedule(0.1)) for gid in range(ncells)]
+
+# Run simulation for 100 ms
+sim.run(100)
+print('Simulation finished')
+
+# Print spike times
+print('spikes:')
+for sp in sim.spikes():
+    print(' ', sp)
+
+# Plot the results
+print("Plotting results ...")
+df_list = []
+for gid in range(ncells):
+    samples, meta = sim.samples(handles[gid])[0]
+    df_list.append(pandas.DataFrame({'t/ms': samples[:, 0], 'U/mV': samples[:, 1], 'Cell': f"cell {gid}"}))
+
+df = pandas.concat(df_list,ignore_index=True)
+seaborn.relplot(data=df, kind="line", x="t/ms", y="U/mV",hue="Cell",ci=None)
+plt.show()
\ No newline at end of file