docs: def save_as_cytoscape_html(tree, out_html, column2states, layout='dagre', name_feature='name',
                             name2colour=None, n2tooltip=None, years=None, is_compressed=True, n2date=None,
                             date_column='Dist. to root'):
      """
      Converts a tree to an html representation using Cytoscape.js.
  
      If categories are specified they are visualised as pie-charts inside the nodes,
      given that each node contains features corresponding to these categories with values being the percentage.
      For instance, given categories ['A', 'B', 'C'], a node with features {'A': 50, 'B': 50}
      will have a half-half pie-chart (half-colored in a colour of A, and half B).
  
      If dist_step is specified, the edges are rescaled accordingly to their dist (node.dist / dist_step),
      otherwise all edges are drawn of the same length.
  
      otherwise all edges are drawn of the same length.
      :param name_feature: str, a node feature whose value will be used as a label
      returns a key to be used for sorting nodes on the same level in the tree.
      :param n2tooltip: dict, TreeNode to str mapping tree nodes to tooltips.
      :param layout: str, name of the layout for Cytoscape.js
      :param name2colour: dict, str to str, category name to HEX colour mapping 
      :param categories: a list of categories for the pie-charts inside the nodes
      :param tree: ete3.Tree
      :param out_html: path where to save the resulting html file.
      """
      graph_name = os.path.splitext(os.path.basename(out_html))[0]
  
      json_dict, clazzes \
          = _tree2json(tree, column2states, name_feature=name_feature,
                       node2tooltip=n2tooltip, years=years, is_compressed=is_compressed, n2date=n2date)
      env = Environment(loader=PackageLoader('pastml'))
      template = env.get_template('pie_tree.js') if is_compressed else env.get_template('pie_tree_simple.js')
  
      clazz2css = {}
      for clazz_list in clazzes:
          n = len(clazz_list)
          css = ''
          for i, cat in enumerate(clazz_list, start=1):
              css += """
                  'pie-{i}-background-color': "{colour}",
                  'pie-{i}-background-size': '{percent}\%',
              """.format(i=i, percent=round(100 / n, 2), colour=name2colour[cat])
          clazz2css[_clazz_list2css_class(clazz_list)] = css
      graph = template.render(clazz2css=clazz2css.items(), elements=json_dict, layout=layout, title=graph_name,
                              years=['{:g}'.format(_) for _ in years])
      slider = env.get_template('time_slider.html').render(min_date=n2date[tree.name], max_date=len(years) - 1,
                                                           name=date_column) \
          if len(years) > 1 else ''
  
      template = env.get_template('index.html')
      page = template.render(graph=graph, title=graph_name, slider=slider)
  
      os.makedirs(os.path.abspath(os.path.dirname(out_html)), exist_ok=True)
      with open(out_html, 'w+') as fp:
          fp.write(page)