docs: def print_head(self, parent_plate_value, plate_values, interval, n=10, print_func=logging.info):
          """
          Print the first n values from the streams in the given time interval.
          The parent plate value is the value of the parent plate,
          and then the plate values are the values for the plate that are to be printed.
          e.g. print_head(None, ("house", "1"))
  
          :param parent_plate_value: The (fixed) parent plate value
          :param plate_values: The plate values over which to loop
          :param interval: The time interval
          :param n: The maximum number of elements to print
          :param print_func: The function used for printing (e.g. logging.info() or print())
          :return: None
          """
          if isinstance(plate_values, Plate):
              self.print_head(parent_plate_value, plate_values.values, interval, n, print_func)
              return
  
          if len(plate_values) == 1 and len(plate_values[0]) == 2 and isinstance(plate_values[0][0], str):
              self.print_head(parent_plate_value, (plate_values,), interval, n, print_func)
              return
  
          found = False
          for plate_value in plate_values:
              combined_plate_value = Plate.combine_values(parent_plate_value, plate_value)
  
              if combined_plate_value not in self._streams:
                  # This can happen if we have created a compound plate and only certain plate values are valid
                  continue
  
              found = True
              print_func("Plate value: {}".format(combined_plate_value))
              data = False
              for k, v in self._streams[combined_plate_value].window(interval).head(n):
                  data = True
                  print_func("{}, {}".format(k, v))
              if not data:
                  print_func("No data")
              print_func("")
          if not found:
              print_func("No streams found for the given plate values")