code: def plot (data, headers=None, pconfig=None):
      
      if headers is None:
          headers = []
      if pconfig is None:
          pconfig = {}
  
      # Allow user to overwrite any given config for this plot
      if 'id' in pconfig and pconfig['id'] and pconfig['id'] in config.custom_plot_config:
          for k, v in config.custom_plot_config[pconfig['id']].items():
              pconfig[k] = v
  
      # Make a datatable object
      dt = table_object.datatable(data, headers, pconfig)
  
      # Collect unique sample names
      s_names = set()
      for d in dt.data:
          for s_name in d.keys():
              s_names.add(s_name)
  
      # Make a beeswarm plot if we have lots of samples
      if len(s_names) >= config.max_table_rows and pconfig.get('no_beeswarm') is not True:
          logger.debug('Plotting beeswarm instead of table, {} samples'.format(len(s_names)))
          warning = '<p class="text-muted"><span class="glyphicon glyphicon-exclamation-sign" ' \
              'title="A beeswarm plot has been generated instead because of the large number of samples. '\
              'See http://multiqc.info/docs/#tables--beeswarm-plots"'\
              ' data-toggle="tooltip"></span> Showing {} samples.</p>'.format(len(s_names))
          return warning + beeswarm.make_plot( dt )
      else:
          return make_table ( dt )
docs: Return HTML for a MultiQC table.
      :param data: 2D dict, first keys as sample names, then x:y data pairs
      :param headers: list of optional dicts with column config in key:value pairs.
      :return: HTML ready to be inserted into the page