docs: def kmean_clustering(network, n_clusters=10, load_cluster=False,
                       line_length_factor=1.25,
                       remove_stubs=False, use_reduced_coordinates=False,
                       bus_weight_tocsv=None, bus_weight_fromcsv=None,
                       n_init=10, max_iter=300, tol=1e-4,
                       n_jobs=1):
      """ Main function of the k-mean clustering approach. Maps an original
      network to a new one with adjustable number of nodes and new coordinates.
  
      Parameters
      ----------
      network : :class:`pypsa.Network
          Container for all network components.
  
      n_clusters : int
          Desired number of clusters.
  
      load_cluster : boolean
          Loads cluster coordinates from a former calculation.
  
      line_length_factor : float
          Factor to multiply the crow-flies distance between new buses in order
          to get new line lengths.
  
      remove_stubs: boolean
          Removes stubs and stubby trees (i.e. sequentially reducing dead-ends).
  
      use_reduced_coordinates: boolean
          If True, do not average cluster coordinates, but take from busmap.
  
      bus_weight_tocsv : str
          Creates a bus weighting based on conventional generation and load
          and save it to a csv file.
  
      bus_weight_fromcsv : str
          Loads a bus weighting from a csv file to apply it to the clustering
          algorithm.
  
      Returns
      -------
      network : pypsa.Network object
          Container for all network components.
      """
      def weighting_for_scenario(x, save=None):
          """
          """
          b_i = x.index
          g = normed(gen.reindex(b_i, fill_value=0))
          l = normed(load.reindex(b_i, fill_value=0))
  
          w = g + l
          weight = ((w * (100000. / w.max())).astype(int)
                    ).reindex(network.buses.index, fill_value=1)
  
          if save:
              weight.to_csv(save)
  
          return weight
  
      def normed(x):
          return (x / x.sum()).fillna(0.)
  
      print('start k-mean clustering')
      # prepare k-mean
      # k-means clustering (first try)
      network.generators.control = "PV"
      network.storage_units.control[network.storage_units.carrier == \
                                    'extendable_storage'] = "PV"
      network.buses['v_nom'] = 380.
      # problem our lines have no v_nom. this is implicitly defined by the
      # connected buses:
      network.lines["v_nom"] = network.lines.bus0.map(network.buses.v_nom)
  
      # adjust the x of the lines which are not 380.
      lines_v_nom_b = network.lines.v_nom != 380
      network.lines.loc[lines_v_nom_b, 'x'] *= \
          (380. / network.lines.loc[lines_v_nom_b, 'v_nom'])**2
      network.lines.loc[lines_v_nom_b, 'v_nom'] = 380.
  
      trafo_index = network.transformers.index
      transformer_voltages = \
          pd.concat([network.transformers.bus0.map(network.buses.v_nom),
                     network.transformers.bus1.map(network.buses.v_nom)], axis=1)
  
      network.import_components_from_dataframe(
          network.transformers.loc[:, [
                  'bus0', 'bus1', 'x', 's_nom', 'capital_cost', 'sub_network', 's_nom_total']]
          .assign(x=network.transformers.x * (380. /
                  transformer_voltages.max(axis=1))**2, length = 1)
          .set_index('T' + trafo_index),
          'Line')
      network.transformers.drop(trafo_index, inplace=True)
  
      for attr in network.transformers_t:
          network.transformers_t[attr] = network.transformers_t[attr]\
              .reindex(columns=[])
  
      # remove stubs
      if remove_stubs:
          network.determine_network_topology()
          busmap = busmap_by_stubs(network)
          network.generators['weight'] = network.generators['p_nom']
          aggregate_one_ports = components.one_port_components.copy()
          aggregate_one_ports.discard('Generator')
          # reset coordinates to the new reduced guys, rather than taking an
          # average (copied from pypsa.networkclustering)
          if use_reduced_coordinates:
              # TODO : FIX THIS HACK THAT HAS UNEXPECTED SIDE-EFFECTS,
              # i.e. network is changed in place!!
              network.buses.loc[busmap.index, ['x', 'y']
                                ] = network.buses.loc[busmap, ['x', 'y']].values
  
          clustering = get_clustering_from_busmap(
              network,
              busmap,
              aggregate_generators_weighted=True,
              aggregate_one_ports=aggregate_one_ports,
              line_length_factor=line_length_factor)
          network = clustering.network
  
      # define weighting based on conventional 'old' generator spatial
      # distribution
      non_conv_types = {
          'biomass',
          'wind_onshore',
          'wind_offshore',
          'solar',
          'geothermal',
          'load shedding',
          'extendable_storage'}
      # Attention: network.generators.carrier.unique()
      gen = (network.generators.loc[(network.generators.carrier
                                     .isin(non_conv_types) == False)]
             .groupby('bus').p_nom.sum()
                                  .reindex(network.buses.index, fill_value=0.) +
             network.storage_units
                                  .loc[(network.storage_units.carrier
                                        .isin(non_conv_types) == False)]
                    .groupby('bus').p_nom.sum()
                    .reindex(network.buses.index, fill_value=0.))
  
      load = network.loads_t.p_set.mean().groupby(network.loads.bus).sum()
  
      # k-mean clustering
  
      # busmap = busmap_by_kmeans(network, bus_weightings=pd.Series(np.repeat(1,
      #       len(network.buses)), index=network.buses.index) , n_clusters= 10)
      # State whether to create a bus weighting and save it, create or not save
      # it, or use a bus weighting from a csv file
      if bus_weight_tocsv is not None:
          weight = weighting_for_scenario(x=network.buses, save=bus_weight_tocsv)
      elif bus_weight_fromcsv is not None:
          weight = pd.Series.from_csv(bus_weight_fromcsv)
          weight.index = weight.index.astype(str)
      else:
          weight = weighting_for_scenario(x=network.buses, save=False)
  
      busmap = busmap_by_kmeans(
          network,
          bus_weightings=pd.Series(weight),
          n_clusters=n_clusters,
          load_cluster=load_cluster,
          n_init=n_init,
          max_iter=max_iter,
          tol=tol,
          n_jobs=n_jobs)
  
      # ToDo change function in order to use bus_strategies or similar
      network.generators['weight'] = network.generators['p_nom']
      aggregate_one_ports = components.one_port_components.copy()
      aggregate_one_ports.discard('Generator')
      clustering = get_clustering_from_busmap(
          network,
          busmap,
          aggregate_generators_weighted=True,
          aggregate_one_ports=aggregate_one_ports)
  
      return clustering