code: def _slice_bounded(self, tuple_key, data_slice):
          
          slices = [el for el in tuple_key if isinstance(el, slice)]
          if any(el.step for el in slices):
              raise Exception("DynamicMap slices cannot have a step argument")
          elif len(slices) not in [0, len(tuple_key)]:
              raise Exception("Slices must be used exclusively or not at all")
          elif not slices:
              return None
  
          sliced = self.clone(self)
          for i, slc in enumerate(tuple_key):
              (start, stop) = slc.start, slc.stop
              if start is not None and start < sliced.kdims[i].range[0]:
                  raise Exception("Requested slice below defined dimension range.")
              if stop is not None and stop > sliced.kdims[i].range[1]:
                  raise Exception("Requested slice above defined dimension range.")
              sliced.kdims[i].soft_range = (start, stop)
          if data_slice:
              if not isinstance(sliced, DynamicMap):
                  return self._dataslice(sliced, data_slice)
              else:
                  from ..util import Dynamic
                  if len(self):
                      slices = [slice(None) for _ in range(self.ndims)] + list(data_slice)
                      sliced = super(DynamicMap, sliced).__getitem__(tuple(slices))
                  dmap = Dynamic(self, operation=lambda obj, **dynkwargs: obj[data_slice],
                                 streams=self.streams)
                  dmap.data = sliced.data
                  return dmap
          return sliced
docs: Slices bounded DynamicMaps by setting the soft_ranges on
          key dimensions and applies data slice to cached and dynamic
          values.