diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml
index 7f6a0804493a7044267df8d5568166a8d1e8f1b3..0239d180112bfb369ca0b69409589a309b2ddce2 100644
--- a/.github/workflows/basic.yml
+++ b/.github/workflows/basic.yml
@@ -165,6 +165,6 @@ jobs:
             python python/example/single_cell_model.py
             python python/example/single_cell_recipe.py
             python python/example/single_cell_stdp.py
-            python python/example/single_cell_swc.py test/unit/swc/pyramidal.swc
+            python python/example/single_cell_swc.py python/example/morph.swc
             python python/example/single_cell_detailed.py python/example/morph.swc
             python python/example/single_cell_detailed_recipe.py python/example/morph.swc
diff --git a/doc/python/morphology.rst b/doc/python/morphology.rst
index 40f7705e603858ed99310e97a4f95d9a7dc61339..fd18f61891d92d2eb261e498f9b7df1418258f9a 100644
--- a/doc/python/morphology.rst
+++ b/doc/python/morphology.rst
@@ -562,7 +562,6 @@ constitute part of the CV boundary point set.
     A :class:`neuroml_morphology_data` object contains a representation of a morphology defined in
     NeuroML.
 
-
     .. py:attribute:: cell_id
        :type: optional<str>
 
@@ -578,6 +577,11 @@ constitute part of the CV boundary point set.
 
        A map from each segment group id to its corresponding collection of segments.
 
+    .. py:attribute:: morphology
+       :type: morphology
+
+       The morphology associated with the :class:`neuroml_morph_data` object.
+
     .. py:method:: segments
 
        Returns a label dictionary with a region entry for each segment, keyed by the segment id (as a string).
diff --git a/python/cells.cpp b/python/cells.cpp
index 8331ed9a78c7f8b1e49080d6acd845ca25906401..493409acbe957d65e998446124210124dd4c60fa 100644
--- a/python/cells.cpp
+++ b/python/cells.cpp
@@ -225,6 +225,12 @@ void register_cells(pybind11::module& m) {
             [](const label_dict_proxy &ld) {
                 return pybind11::make_key_iterator(ld.cache.begin(), ld.cache.end());},
             pybind11::keep_alive<0, 1>())
+        .def("append", [](label_dict_proxy& l, const label_dict_proxy& other, const char* prefix) {
+                l.import(other, prefix);
+            },
+            "other"_a, "The label_dict to be imported"
+            "prefix"_a="", "optional prefix appended to the region and locset labels",
+            "Import the entries of a another label dictionary with an optional prefix.")
         .def_readonly("regions", &label_dict_proxy::regions,
              "The region definitions.")
         .def_readonly("locsets", &label_dict_proxy::locsets,
diff --git a/python/example/morph.nml b/python/example/morph.nml
new file mode 100644
index 0000000000000000000000000000000000000000..ea58feb735e52ea5601f224896a7e0f991528c78
--- /dev/null
+++ b/python/example/morph.nml
@@ -0,0 +1,72 @@
+<neuroml xmlns="http://www.neuroml.org/schema/neuroml2">
+<morphology id="m1">
+    <segment id="0">
+        <proximal x="0" y="0" z="0" diameter="4"/>
+        <distal  x="40" y="0" z="0" diameter="4"/>
+    </segment>
+    <segment id="1">
+        <parent segment="0"/>
+        <proximal x="40" y="0" z="0" diameter="1.6"/>
+        <distal   x="80" y="0" z="0" diameter="1.6"/>
+    </segment>
+    <segment id="2">
+        <parent segment="1"/>
+        <proximal x="80"  y="0"  z="0" diameter="1.6"/>
+        <distal   x="120" y="-5" z="0" diameter="1.6"/>
+    </segment>
+    <segment id="3">
+        <parent segment="2"/>
+        <proximal x="120" y="-5" z="0" diameter="1.6"/>
+        <distal   x="200" y="40" z="0" diameter="0.8"/>
+    </segment>
+    <segment id="4">
+        <parent segment="3"/>
+        <proximal x="200" y="40" z="0" diameter="0.8"/>
+        <distal   x="260" y="60" z="0" diameter="0.4"/>
+    </segment>
+    <segment id="5">
+        <parent segment="2"/>
+        <proximal x="120" y="-5"  z="0" diameter="1"/>
+        <distal   x="190" y="-30" z="0" diameter="1"/>
+    </segment>
+    <segment id="6">
+        <parent segment="5"/>
+        <proximal x="190" y="-30" z="0" diameter="1"/>
+        <distal   x="240" y="-70" z="0" diameter="0.4"/>
+    </segment>
+    <segment id="7">
+        <parent segment="5"/>
+        <proximal x="190" y="-30" z="0" diameter="1"/>
+        <distal   x="230" y="-10" z="0" diameter="0.4"/>
+    </segment>
+    <segment id="8">
+        <parent segment="7"/>
+        <proximal x="230" y="-10" z="0" diameter="0.4"/>
+        <distal   x="360" y="-20" z="0" diameter="0.4"/>
+    </segment>
+    <segment id="9">
+        <parent segment="0" fractionAlong="0.0"/>
+        <proximal x="0"   y="0" z="0" diameter="4"/>
+        <distal   x="-70" y="0" z="0" diameter="0.8"/>
+    </segment>
+    <segment id="10">
+        <parent segment="9"/>
+        <proximal x="-70"  y="0" z="0" diameter="0.8"/>
+        <distal   x="-100" y="0" z="0" diameter="0.8"/>
+    </segment>
+    <segmentGroup id="soma">
+        <member segment="0"/>
+    </segmentGroup>
+    <segmentGroup id="axon">
+        <member segment="9"/>
+        <member segment="10"/>
+    </segmentGroup>
+    <segmentGroup id="dend">
+        <member segment="1"/>
+        <member segment="2"/>
+        <member segment="3"/>
+        <member segment="4"/>
+        <member segment="5"/>
+    </segmentGroup>
+</morphology>
+</neuroml>
diff --git a/python/example/single_cell_nml.py b/python/example/single_cell_nml.py
new file mode 100755
index 0000000000000000000000000000000000000000..cb5e668ff9177fd4a85c6b0c42c151a0cef9bfc1
--- /dev/null
+++ b/python/example/single_cell_nml.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python3
+import arbor
+from arbor import mechanism as mech
+from arbor import location as loc
+import pandas, seaborn
+import sys
+
+# Load a cell morphology from an nml file.
+# Example present here: morph.nml
+if len(sys.argv) < 2:
+    print("No NeuroML file passed to the program")
+    sys.exit(0)
+
+filename = sys.argv[1]
+
+# Read the NeuroML morphology from the file.
+morpho_nml = arbor.neuroml(filename)
+
+# Read the morphology data associated with morphology "m1".
+morpho_data = morpho_nml.morphology("m1")
+
+# Get the morphology.
+morpho = morpho_data.morphology
+
+# Get the region label dictionaries associated with the morphology.
+morpho_segments = morpho_data.segments()
+morpho_named = morpho_data.named_segments()
+morpho_groups = morpho_data.groups()
+
+# Create new label dict add to it all the NeuroML dictionaries.
+labels = arbor.label_dict()
+labels.append(morpho_segments)
+labels.append(morpho_named)
+labels.append(morpho_groups)
+
+# Add locsets to the label dictionary. 
+labels['stim_site'] = '(location 1 0.5)' # site for the stimulus, in the middle of branch 1.
+labels['axon_end']  = '(restrict (terminal) (region "axon"))' # end of the axon.
+labels['root']      = '(root)' # the start of the soma in this morphology is at the root of the cell.
+
+# Optional: print out the regions and locsets available in the label dictionary.
+print("Label dictionary regions: ", labels.regions, "\n")
+print("Label dictionary locsets: ", labels.locsets, "\n")
+
+decor = arbor.decor()
+
+# Set initial membrane potential to -55 mV
+decor.set_property(Vm=-55)
+# Use Nernst to calculate reversal potential for calcium.
+decor.set_ion('ca', method=mech('nernst/x=ca'))
+#decor.set_ion('ca', method='nernst/x=ca')
+# hh mechanism on the soma and axon.
+decor.paint('"soma"', 'hh')
+decor.paint('"axon"', 'hh')
+# pas mechanism the dendrites.
+decor.paint('"dend"', 'pas')
+# Increase resistivity on dendrites.
+decor.paint('"dend"', rL=500)
+# Attach stimuli that inject 4 nA current for 1 ms, starting at 3 and 8 ms.
+decor.place('"root"', arbor.iclamp(10, 1, current=5))
+decor.place('"stim_site"', arbor.iclamp(3, 1, current=0.5))
+decor.place('"stim_site"', arbor.iclamp(10, 1, current=0.5))
+decor.place('"stim_site"', arbor.iclamp(8, 1, current=4))
+# Detect spikes at the soma with a voltage threshold of -10 mV.
+decor.place('"axon_end"', arbor.spike_detector(-10))
+
+# Create the policy used to discretise the cell into CVs.
+# Use a single CV for the soma, and CVs of maximum length 1 μm elsewhere.
+soma_policy = arbor.cv_policy_single('"soma"')
+dflt_policy = arbor.cv_policy_max_extent(1.0)
+policy = dflt_policy | soma_policy
+decor.discretization(policy)
+
+# Combine morphology with region and locset definitions to make a cable cell.
+cell = arbor.cable_cell(morpho, labels, decor)
+
+print(cell.locations('"axon_end"'))
+
+# Make single cell model.
+m = arbor.single_cell_model(cell)
+
+# Attach voltage probes that sample at 50 kHz.
+m.probe('voltage', where='"root"',  frequency=50000)
+m.probe('voltage', where='"stim_site"',  frequency=50000)
+m.probe('voltage', where='"axon_end"', frequency=50000)
+
+# Simulate the cell for 15 ms.
+tfinal=15
+m.run(tfinal)
+print("Simulation done.")
+
+# Print spike times.
+if len(m.spikes)>0:
+    print('{} spikes:'.format(len(m.spikes)))
+    for s in m.spikes:
+        print('  {:7.4f}'.format(s))
+else:
+    print('no spikes')
+
+# Plot the recorded voltages over time.
+print("Plotting results ...")
+df_list = []
+for t in m.traces:
+    df_list.append(pandas.DataFrame({'t/ms': t.time, 'U/mV': t.value, 'Location': str(t.location), "Variable": t.variable}))
+
+df = pandas.concat(df_list)
+
+seaborn.relplot(data=df, kind="line", x="t/ms", y="U/mV",hue="Location",col="Variable",ci=None).savefig('single_cell_nml.svg')
diff --git a/python/example/single_cell_swc.py b/python/example/single_cell_swc.py
index 5584b9f5d41176679339ef2a9763cb05113b5cda..63113384db0b86af3ed419f3607d790aef09b5a8 100755
--- a/python/example/single_cell_swc.py
+++ b/python/example/single_cell_swc.py
@@ -17,7 +17,7 @@ import pandas, seaborn
 import sys
 
 # Load a cell morphology from an swc file.
-# Example present here: ../../test/unit/swc/pyramidal.swc
+# Example present here: morph.swc
 if len(sys.argv) < 2:
     print("No SWC file passed to the program")
     sys.exit(0)
diff --git a/python/proxy.hpp b/python/proxy.hpp
index d47ab761b745d7947bd80ccd65d1f8d00ff5582d..1d4d059989cfe2e20196367fa7ea41472f8c9966 100644
--- a/python/proxy.hpp
+++ b/python/proxy.hpp
@@ -23,12 +23,31 @@ struct label_dict_proxy {
         }
     }
 
-    label_dict_proxy(const arb::label_dict& label_dict): dict(label_dict) {}
+    label_dict_proxy(const arb::label_dict& label_dict): dict(label_dict) {
+        for (const auto& [l, reg]: dict.regions()) {
+            regions.push_back(l);
+        }
+        for (const auto& [l, ls]: dict.locsets()) {
+            locsets.push_back(l);
+        }
+    }
 
     std::size_t size() const  {
         return locsets.size() + regions.size();
     }
 
+    void import(const label_dict_proxy& other, std::string prefix) {
+        regions.clear();
+        locsets.clear();
+        dict.import(other.dict, prefix);
+        for (const auto& [l, reg]: dict.regions()) {
+            regions.push_back(l);
+        }
+        for (const auto& [l, ls]: dict.locsets()) {
+            locsets.push_back(l);
+        }
+    }
+
     void set(const char* name, const char* desc) {
         using namespace std::string_literals;
         // The following code takes an input name and a region or locset