def add_colons(df, id_name='', col_types={}):
    """
    Adds the colons to column names before neo4j import (presumably removed by `remove_colons` to make queryable).
    User can also specify  a name for the ':ID' column and data types for property columns.

    :param df: DataFrame, the neo4j import data without colons in it (e.g. to make it queryable).
    :param id_name: String, name for the id property.  If importing a CSV into neo4j without this property,
                    Neo4j mayuse its own internal id's losing this property.
    :param col_types: dict, data types for other columns in the form of column_name:data_type
    :return: DataFrame, with neo4j compatible column headings
    """
    reserved_cols = ['id', 'label', 'start_id', 'end_id', 'type']

    # Get the reserved column names that need to be changed
    to_change = [c for c in df.columns if c.lower() in reserved_cols]
    if not to_change:
        raise ValueError("Neo4j Reserved columns (['id', 'label' 'start_id', 'end_id', 'type'] not " +
                         "found in DataFrame")

    # Add any column names that need to be types
    to_change += [c for c in df.columns if c in col_types.keys()]

    change_dict = {}
    for name in to_change:
        # Reserved column names go after the colon
        if name.lower() in reserved_cols:
            if name.lower() == 'id':
                new_name = id_name + ':' + name.upper()
            else:
                new_name = ':' + name.upper()
        else:
            # Data types go after the colon, while names go before.
            new_name = name + ':' + col_types[name].upper()
        change_dict.update({name: new_name})

    return df.rename(columns=change_dict)