def create_req_and_opt_graph(req_comp_g_contracted, complete_g, circuit_rpp, GranularConnector_EdgeList):
    """
    Creates a graph with required and optional edges delineated for visualization
    Args:
        req_comp_g_contracted (NetworkX MultiDiGraph): required component graph containing contracted edges
            generated by initialize_rpp.InnerAndOuterToEdgeListFile
        complete_g (NetworkX MultiDiGraph): complete street network graph
            generated by initialize_rpp.InnerAndOuterToEdgeListFile
        circuit_rpp (list): rpp circuit generated by postman_problems.solver.rpp and
            edited by circuit_path_string_to_int
    Returns:
        final_graph (NetworkX DiGraph): graph of route with optional and required edges delineated
        print statements with required and optional edge breakdown
    """
    final_graph = req_comp_g_contracted.copy()
    unexpanded_edges = 0
    unexpanded_edges_list = []
    granular_connector_edges = 0
    granular_connector_edges_list = []
    granular_req_edges = 0
    granular_req_edges_list = []
    optional_edges = 0
    optional_edges_list = []
    for e in circuit_rpp:
        if [e[0], e[1]] not in unexpanded_edges_list:
            unexpanded_edges+=1
            unexpanded_edges_list+=[[e[0], e[1]]]
        # add granular optional edges to final_graph
        path = e[3]['path']
        for pair in list(zip(path[:-1], path[1:])):
            if (req_comp_g_contracted.has_edge(pair[0], pair[1])):
                edge = req_comp_g_contracted[pair[0]][pair[1]][0]
                if [pair[0], pair[1]] in GranularConnector_EdgeList:
                    final_graph[pair[0]][pair[1]][0]['granular_type'] = 'req street and connector'
                    if [pair[0], pair[1]] not in granular_connector_edges_list:
                        granular_connector_edges+=1
                        granular_connector_edges_list+=[[pair[0], pair[1]]]
                    elif 1 in req_comp_g_contracted[pair[0]][pair[1]]:
                            granular_connector_edges+=1
                else:
                    if [pair[0], pair[1]] not in granular_req_edges_list:
                        final_graph[pair[0]][pair[1]][0]['granular_type'] = 'req street'
                        granular_req_edges+=1
                        granular_req_edges_list+=[[pair[0], pair[1]]]
            else:
                if [pair[0], pair[1]] in GranularConnector_EdgeList:
                    if [pair[0], pair[1]] not in granular_connector_edges_list:
                        final_graph.add_edge(pair[0], pair[1], granular=True, granular_type='connector')
                        granular_connector_edges+=1
                        granular_connector_edges_list+=[[pair[0], pair[1]]]
                elif [pair[0], pair[1]] not in optional_edges_list:
                    final_graph.add_edge(pair[0], pair[1], granular=True, granular_type='optional')
                    optional_edges+=1
                    optional_edges_list+=[[pair[0], pair[1]]]
                else:
                    print(pair)
        for n in path:
            final_graph.add_node(n, y=complete_g.nodes[n]['y'], x=complete_g.nodes[n]['x'])
    print('Edges in Circuit')
    print('\tTotal Unexpanded Edges: {}'.format(unexpanded_edges))
    print('\tTotal Edges (All Contracted Edges Granularized): {}'.format(granular_connector_edges+granular_req_edges+optional_edges))
    print('\t\tGranular Connector Edges: {}'.format(granular_connector_edges))
    print('\t\tGranular Required Edges: {}'.format(granular_req_edges))
    print('\t\tGranular Optional Edges: {}'.format(optional_edges))
    return final_graph