code: def get_ranks_for_environment_and_phenotypes(environment, phenotypes, k=15):
      
      # Create list of all niches and all phenotypes, in phenotype format
      niches = flatten_array(environment)
      phenotypes = flatten_array(phenotypes)
  
      types = set(phenotypes+niches)
  
      types.discard("-0b1")  # We'll handle this specially
      types.discard("0b0")  # We'll handle this specially
  
      # Do all clustering ahead of time so colors remain consistent.
      ranks = generate_ranks(list(types), k)
  
      ranks["-0b1"] = -1  # The empty phenotype/niche should always be rank -1
      ranks["0b0"] = 0  # The empty phenotype/niche should always be rank 0
  
      return ranks
docs: Takes an EnvironmentFile and a 2d array represemtimg phenotypes at each
      location. Optionally also takes an integer indicating the maximum number
      of clusters allowed to be created (default 15).
  
      Environment is expected to already have been converted to binary numbers
      (generally because this is being called by rank_environment_and_phenotypes)
  
      Return a dictionary mapping binary strings representing groups of
      resources/tasks that are present/performed in a given cell to integers
      indicating the ranked order of the cluster they're part of.