def code_features(E,parts,spec_avg_parts=None,
                  lower_quantile=.9,upper_quantile=1.):
    """
    Part coding for an utterance using the waliji parts
    Optionally will produce the spectrogram associated with the features
    this is important for visualizing and diagnosing what this function is doing
    """
    num_features = E.shape[0]
    num_freq_bands = num_features/8
    edge_feature_row_breaks = np.arange(9,dtype=int)*num_freq_bands
    patch_height, patch_width = parts[0].log_template.shape
    patch_height /= 8
    bps,all_patch_rows,all_patch_cols = elf.extract_local_features_tied(E,patch_height,
                                                                       patch_width, lower_quantile,
                                                                       upper_quantile,
                                                                       edge_feature_row_breaks,
                                                                       segment_ms=500,
                                                                       hop_ms = 5)
    # initially set all features to background
    feature_map = -1*np.ones((num_freq_bands,E.shape[1]),dtype=np.int8)
    # read in all the parts
    patch_ids = np.array(
        tuple(
            np.argmax(
                tuple(
    (bp*part.log_template + (1-bp)*part.log_invtemplate).sum()
    for part in parts)).astype(np.uint16)
    for bp in bps))
    feature_map[all_patch_rows,all_patch_cols] = patch_ids
    if spec_avg_parts is not None:
        S_coded = S_code_features(feature_map,patch_ids,all_patch_rows,all_patch_cols,
                                spec_avg_parts)
        return feature_map,S_coded
    return feature_map
 E, edge_feature_row_breaks,\
   edge_orientations = esp._edge_map_no_threshold(S)
 esp._edge_map_threshold_segments(E,
                                  20,
                                  1,
                                  threshold=.7,
                                  edge_orientations = edge_orientations,
                                  edge_feature_row_breaks = edge_feature_row_breaks)
 if lower_cutoff == 10:
     np.save(tmp_data_path+str(s_idx)+'E.npy',E)
 patch_width = 5
 patch_height = 5
 upper_cutoff = 200
 bp,all_patch_rows,all_patch_cols = elf.extract_local_features_tied(E,patch_height,
                                                                    patch_width, lower_cutoff,
                                                                    upper_cutoff,
                                                                    edge_feature_row_breaks,
     )
 # get rid of those that are just hugging the border
 use_indices = np.logical_and(all_patch_rows < E.shape[0] - patch_height,
                              all_patch_cols < E.shape[1] - patch_width)
 bp = bp[use_indices]
 all_patch_rows = all_patch_rows[use_indices]
 all_patch_cols = all_patch_cols[use_indices]
 bps = np.vstack((bps,bp.astype(np.uint8)))
 s_idx_list.extend(bp.shape[0] *[s_idx])
 # need to capture the fact that we have bigger patches for the spectrogram
 patch_row_indices = elf.generate_patch_row_indices(all_patch_rows,patch_height+1,patch_width+1)-1
 patch_col_indices = elf.generate_patch_col_indices(all_patch_cols,patch_height+1,patch_width+1)
 # np.save(tmp_data_path+str(s_idx)+'all_patch_cols_%d.npy' %lower_cutoff,all_patch_cols)
 # s_windows = np.lib.stride_tricks.as_strided(s,shape=(len(s)-patch_width*num_window_samples,patch_width*num_window_samples),
                                  kernel_length)
 E, edge_feature_row_breaks,\
   edge_orientations = esp._edge_map_no_threshold(S)
 esp._edge_map_threshold_segments(E,
                                  40,
                                  1,
                                  threshold=.3,
                                  edge_orientations = edge_orientations,
                                  edge_feature_row_breaks = edge_feature_row_breaks)
 patch_width = 5
 patch_height = 5
 lower_quantile = .9
 upper_quantile = 1.
 bp,all_patch_rows,all_patch_cols = elf.extract_local_features_tied(E,patch_height,
                                                                    patch_width, lower_quantile,
                                                                    upper_quantile,
                                                                    edge_feature_row_breaks,
                                                                    segment_ms=500,
                                                                    hop_ms = 5)
 bps = np.vstack((bps,bp.astype(np.uint8)))
 s_idx_list.extend(bp.shape[0] *[s_idx])
 # need to capture the fact that we have bigger patches for the spectrogram
 patch_row_indices = elf.generate_patch_row_indices(all_patch_rows,patch_height+1,patch_width+1)-1
 patch_col_indices = elf.generate_patch_col_indices(all_patch_cols,patch_height+1,patch_width+1)
 np.save(tmp_data_path+str(s_idx)+'all_patch_cols.npy',all_patch_cols)
 s_windows = np.lib.stride_tricks.as_strided(s,shape=(len(s)-patch_width*num_window_samples,patch_width*num_window_samples),
                                             strides=(s.itemsize,s.itemsize))
 patch_s_windows = s_windows[all_patch_cols * 80]
 np.save(tmp_data_path+str(s_idx)+'bp.npy',bp)
 np.save(tmp_data_path+str(s_idx)+'patch_s_windows.npy',patch_s_windows)
 np.save(tmp_data_path+str(s_idx)+'spec_patch.npy',S[patch_row_indices,patch_col_indices].reshape(bp.shape[0],patch_height+1,patch_width+1))
 # keeps track of which parts are the spectrogram are being