class_docstr: MultiInterface allows wrapping around a list of tabular datasets
  including dataframes, the columnar dictionary format or 2D tabular
  NumPy arrays. Using the split method the list of tabular data can
  be split into individual datasets.
  
  The interface makes the data appear a list of tabular datasets as
  a single dataset. The interface may be used to represent geometries
  so the behavior depends on the type of geometry being represented.
class_docstr_tok: ["MultiInterface","allows","wrapping","around","a","list","of","tabular","datasets","including","dataframes",",","the","columnar","dictionary","format","or","2D","tabular","NumPy","arrays",".","Using","the","split","method","the","list","of","tabular","data","can","be","split","into","individual","datasets",".","The","interface","makes","the","data","appear","a","list","of","tabular","datasets","as","a","single","dataset",".","The","interface","may","be","used","to","represent","geometries","so","the","behavior","depends","on","the","type","of","geometry","being","represented","."]
code: def groupby(
      cls, dataset, dimensions, container_type, group_type, **kwargs
  ):
      # Get dimensions information
      dimensions = [dataset.get_dimension(d) for d in dimensions]
      kdims = [kdim for kdim in dataset.kdims if kdim not in dimensions]
  
      # Update the kwargs appropriately for Element group types
      group_kwargs = {}
      group_type = list if group_type == "raw" else group_type
      if issubclass(group_type, Element):
          group_kwargs.update(util.get_param_values(dataset))
          group_kwargs["kdims"] = kdims
      group_kwargs.update(kwargs)
  
      # Find all the keys along supplied dimensions
      values = []
      for d in dimensions:
          if not cls.isscalar(dataset, d, True):
              raise ValueError(
                  "MultiInterface can only apply groupby "
                  "on scalar dimensions, %s dimension "
                  "is not scalar" % d
              )
          vals = cls.values(dataset, d, False, True)
          values.append(vals)
      values = tuple(values)
  
      # Iterate over the unique entries applying selection masks
      from . import Dataset
  
      ds = Dataset(values, dimensions)
      keys = (
          tuple(vals[i] for vals in values) for i in range(len(vals))
      )
      grouped_data = []
      for unique_key in util.unique_iterator(keys):
          mask = ds.interface.select_mask(
              ds, dict(zip(dimensions, unique_key))
          )
          selection = [data for data, m in zip(dataset.data, mask) if m]
          group_data = group_type(selection, **group_kwargs)
          grouped_data.append((unique_key, group_data))
  
      if issubclass(container_type, NdMapping):
          with item_check(False), sorted_context(False):
              return container_type(grouped_data, kdims=dimensions)
      else:
          return container_type(grouped_data)
  
imports: import numpy
  from ..None import util
  from ..element import Element
  from ..ndmapping import NdMapping, item_check, sorted_context
  from .dictionary import DictInterface
  from .interface import DataError, Interface
label_desc: Use image node_id 14 for calling the MultiInterface obj's underlying member method code with example usage: obj.groupby(cls, dataset, dimensions, container_type, group_type) and returns: container_type, container_type