docs: def filter_user_term_matrix(user_term_matrix, annotated_nodes, label_to_topic, max_number_of_labels=None):
      """
      Filters out labels that are either too rare, or have very few representatives.
  
      Inputs:  - user_term_matrix: A user-to-term matrix in scipy sparse matrix format.
               - annotated_nodes: A numpy array containing graph nodes.
               - label_to_topic: A python dictionary that maps a numerical label to a string topic/keyword.
               - max_number_of_labels: The upper limit for the number of labels.
  
      Outputs: - user_term_matrix: The filtered user-to-term matrix in scipy sparse matrix format.
               - annotated_nodes: A numpy array containing graph nodes.
               - label_to_topic: A python dictionary that maps a numerical label to a string topic/keyword.
      """
      # Aggregate edges and eliminate zeros.
      user_term_matrix = user_term_matrix.tocsr()
      user_term_matrix.eliminate_zeros()
  
      ####################################################################################################################
      # Enforce max number of labels if required.
      ####################################################################################################################
      # Form matrix that indicates which user-label pairs are nonzero.
      temp_matrix = copy.copy(user_term_matrix)
      temp_matrix.data = np.ones_like(temp_matrix.data).astype(np.int64)
      temp_matrix.astype(np.int64)
  
      # Calculate the label-user counts.
      label_frequencies = temp_matrix.sum(axis=0)
      index = np.argsort(np.squeeze(np.asarray(label_frequencies)))
  
      # Apply max number of labels cutoff.
      if max_number_of_labels is not None:
          if index.size > max_number_of_labels:
              index = index[:index.size-max_number_of_labels]
      else:
          index = np.array(list())
  
      # If there are zero samples of a label, remove them from both the matrix and the label-to-topic map.
  
      # percentile = 90
      # p = np.percentile(label_frequencies, percentile)
      # index = np.where(label_frequencies <= p)[1]
      if index.size > 0:
          index = np.squeeze(np.asarray(index))
          index = np.setdiff1d(np.arange(label_frequencies.size), index)
          user_term_matrix = user_term_matrix[:, index]
          temp_map = dict()
          counter = 0
          for i in index:
              temp_map[counter] = label_to_topic[i]
              counter += 1
          label_to_topic = temp_map
  
      # print(user_term_matrix.getnnz())
      # print(user_term_matrix.shape)
  
      # Perform tf-idf on all matrices.
      user_term_matrix = augmented_tf_idf(user_term_matrix)
  
      ####################################################################################################################
      # Most topics are heavy-tailed. For each topic, threshold to annotate.
      ####################################################################################################################
      user_term_nnz = user_term_matrix.getnnz()
      # percentile = 80
      percentile = 50
  
      while True:
          matrix_row = list()
          matrix_col = list()
          extend_matrix_row = matrix_row.extend
          extend_matrix_col = matrix_col.extend
  
          user_term_matrix = sparse.csc_matrix(user_term_matrix)
          for topic in range(user_term_matrix.shape[1]):
              col = user_term_matrix.getcol(topic)
              p = np.percentile(col.data, percentile)
              index = col.indices[col.data >= p]
              extend_matrix_row(index)
              extend_matrix_col(topic*np.ones_like(index))
          matrix_row = np.array(matrix_row, dtype=np.int64)
          matrix_col = np.array(matrix_col, dtype=np.int64)
          matrix_data = np.ones_like(matrix_row, dtype=np.int8)
          user_term_matrix = sparse.coo_matrix((matrix_data, (matrix_row, matrix_col)), shape=user_term_matrix.shape)
          user_term_matrix = sparse.csr_matrix(user_term_matrix)
  
          if (user_term_matrix.getnnz() > user_term_nnz/10) and (user_term_matrix.shape[1] > 1):
              break
          else:
              percentile -= 10
              if percentile <= 10:
                  break
  
      # print(user_term_matrix.getnnz())
      # print(user_term_matrix.shape)
  
      ####################################################################################################################
      # If there is a small number of samples of a label, remove them from both the matrix and the label-to-topic map.
      ####################################################################################################################
      user_term_nnz = user_term_matrix.getnnz()
  
      minimum_frequency = 3
  
      while True:
          # Form matrix that indicates which user-label pairs are nonzero.
          temp_matrix = copy.copy(user_term_matrix)
          temp_matrix.data = np.ones_like(temp_matrix.data).astype(np.int64)
          temp_matrix.astype(np.int64)
  
          label_frequencies = temp_matrix.sum(axis=0)
  
          # index = np.where(label_frequencies < 31)[1]  # Fewer than 10.
          index = np.where(label_frequencies < minimum_frequency)[1]  # Fewer than 10.
          if index.shape[1] > 0:
              index = np.squeeze(np.asarray(index))
              index = np.setdiff1d(np.arange(label_frequencies.size), index)
              user_term_matrix = user_term_matrix[:, index]
              temp_map = dict()
              counter = 0
              for i in index:
                  temp_map[counter] = label_to_topic[i]
                  counter += 1
              label_to_topic = temp_map
  
          if (user_term_matrix.getnnz() > user_term_nnz/2) and (user_term_matrix.shape[1] > 1):
              break
          else:
              minimum_frequency -= 1
              if minimum_frequency <= 1:
                  break
  
      # print(user_term_matrix.getnnz())
      # print(user_term_matrix.shape)
  
      # print(len(label_to_topic))
  
      return user_term_matrix, annotated_nodes, label_to_topic