diff --git a/gwinc/nb.py b/gwinc/nb.py
index 19ce472e0b193a1fdda0f263e5a1a968f5705127..56baa8bfd5582f2913ed3e259791b81d0a4ca921 100644
--- a/gwinc/nb.py
+++ b/gwinc/nb.py
@@ -418,13 +418,33 @@ class Budget(Noise):
         return name
 
     def __getitem__(self, name):
+        """Get a (possibly nested) sub-BudgetItem.
+
+        """
+        try:
+            name, rest = name.split('.', 1)
+        except ValueError:
+            rest = None
         try:
-            return self._noise_objs[name]
+            o = self._noise_objs[name]
         except KeyError:
             try:
-                return self._cal_objs[name]
+                o = self._cal_objs[name]
             except KeyError:
                 raise KeyError("unknown noise or cal name '{}".format(name))
+        if rest:
+            return o[rest]
+        else:
+            return o
+
+    def get(self, key, default=None):
+        """Get a (possibly nested) sub-BudgetItem.
+
+        """
+        try:
+            return self[key]
+        except KeyError:
+            return default
 
     def keys(self):
         """Iterate over budget noise names."""
diff --git a/gwinc/trace.py b/gwinc/trace.py
index d113b98580188853493a4bfc5bf330c6a0bf2929..a15d5590cc86fcc758b655b8bb7053b7903114ba 100644
--- a/gwinc/trace.py
+++ b/gwinc/trace.py
@@ -61,8 +61,23 @@ class BudgetTrace:
             raise AttributeError
 
     def __getitem__(self, name):
-        """get budget trace by name"""
-        return self._bdict[name]
+        """get budget trace by name
+
+        """
+        try:
+            name, rest = name.split('.', 1)
+            return self._bdict[name][rest]
+        except ValueError:
+            return self._bdict[name]
+
+    def get(self, key, default=None):
+        """get a (possibly nested) Trace item.
+
+        """
+        try:
+            return self[key]
+        except KeyError:
+            return default
 
     def items(self):
         """iterator of budget (name, trace) tuples"""