code: def range(self, dimension, data_range=True, dimension_range=True):
          
          dimension = self.get_dimension(dimension)
          if dimension is None or (not data_range and not dimension_range):
              return (None, None)
          elif all(util.isfinite(v) for v in dimension.range) and dimension_range:
              return dimension.range
          elif data_range:
              if dimension in self.kdims+self.vdims:
                  dim_vals = self.dimension_values(dimension.name)
                  lower, upper = util.find_range(dim_vals)
              else:
                  dname = dimension.name
                  match_fn = lambda x: dname in x.kdims + x.vdims
                  range_fn = lambda x: x.range(dname)
                  ranges = self.traverse(range_fn, [match_fn])
                  lower, upper = util.max_range(ranges)
          else:
              lower, upper = (np.NaN, np.NaN)
          if not dimension_range:
              return lower, upper
          return util.dimension_range(lower, upper, dimension.range, dimension.soft_range)
docs: Return the lower and upper bounds of values along dimension.
  
          Args:
              dimension: The dimension to compute the range on.
              data_range (bool): Compute range from data values
              dimension_range (bool): Include Dimension ranges
                  Whether to include Dimension range and soft_range
                  in range calculation
  
          Returns:
              Tuple containing the lower and upper bound