def visualize_sample(nusc: NuScenes,
                     sample_token: str,
                     gt_boxes: EvalBoxes,
                     pred_boxes: EvalBoxes,
                     nsweeps: int = 1,
                     conf_th: float = 0.4,
                     pc_range: list = [-30.0, -30.0, -4.0, 30.0, 30.0, 4.0],
                     verbose: bool = True,
                     savepath: str = None,
                     traj_use_perstep_offset: bool = True,
                     data_root='data/nuscenes/',
                     map_pc_range: list = [-15.0, -30.0, -4.0, 15.0, 30.0, 4.0],
                     padding_value=-10000,
                     map_classes=['divider', 'ped_crossing', 'boundary'],
                     map_fixed_ptsnum_per_line=20,
                     gt_format=['fixed_num_pts'],
                     colors_plt = ['cornflowerblue', 'royalblue', 'slategrey'],
                     pred_data = None) -> None:
    """
    Visualizes a sample from BEV with annotations and detection results.
    :param nusc: NuScenes object.
    :param sample_token: The nuScenes sample token.
    :param gt_boxes: Ground truth boxes grouped by sample.
    :param pred_boxes: Prediction grouped by sample.
    :param nsweeps: Number of sweeps used for lidar visualization.
    :param conf_th: The confidence threshold used to filter negatives.
    :param eval_range: Range in meters beyond which boxes are ignored.
    :param verbose: Whether to print to stdout.
    :param savepath: If given, saves the the rendering here instead of displaying.
    """
    # Retrieve sensor & pose records.
    sample_rec = nusc.get('sample', sample_token)
    sd_record = nusc.get('sample_data', sample_rec['data']['LIDAR_TOP'])
    cs_record = nusc.get('calibrated_sensor', sd_record['calibrated_sensor_token'])
    pose_record = nusc.get('ego_pose', sd_record['ego_pose_token'])
    # Get boxes.
    boxes_gt_global = gt_boxes[sample_token]
    boxes_est_global = pred_boxes[sample_token]
    # Map GT boxes to lidar.
    boxes_gt = boxes_to_sensor(boxes_gt_global, pose_record, cs_record)
    # Map EST boxes to lidar.
    boxes_est = boxes_to_sensor(boxes_est_global, pose_record, cs_record)
    # Add scores to EST boxes.
    for box_est, box_est_global in zip(boxes_est, boxes_est_global):
        box_est.score = box_est_global.detection_score

    # Init axes.
    fig, axes = plt.subplots(1, 1, figsize=(4, 4))
    plt.xlim(xmin=-30, xmax=30)
    plt.ylim(ymin=-30, ymax=30)

    # Show Pred Map
    result_dic = pred_data['map_results'][sample_token]['vectors']

    for vector in result_dic:
        if vector['confidence_level'] < 0.6:
            continue
        pred_pts_3d = vector['pts']
        pred_label_3d = vector['type']
        pts_x = np.array([pt[0] for pt in pred_pts_3d])
        pts_y = np.array([pt[1] for pt in pred_pts_3d])

        axes.plot(pts_x, pts_y, color=colors_plt[pred_label_3d],linewidth=1,alpha=0.8,zorder=-1)
        axes.scatter(pts_x, pts_y, color=colors_plt[pred_label_3d],s=1,alpha=0.8,zorder=-1)  

    # ignore_list = ['barrier', 'motorcycle', 'bicycle', 'traffic_cone']
    ignore_list = ['barrier', 'bicycle', 'traffic_cone']

    # Show Pred boxes.
    for i, box in enumerate(boxes_est):
        if box.name in ignore_list:
            continue
        # Show only predictions with a high score.
        assert not np.isnan(box.score), 'Error: Box score cannot be NaN!'
        if box.score < conf_th or abs(box.center[0]) > 15 or abs(box.center[1]) > 30:
            continue
        box.render(axes, view=np.eye(4), colors=('tomato', 'tomato', 'tomato'), linewidth=1, box_idx=None)
        # if box.name in ['pedestrian']:
        #     continue
        if traj_use_perstep_offset:
            mode_idx = [0, 1, 2, 3, 4, 5]
            box.render_fut_trajs_grad_color(axes, linewidth=1, mode_idx=mode_idx, fut_ts=6, cmap='autumn')
        else:
            box.render_fut_trajs_coords(axes, color='tomato', linewidth=1)

    # Show Planning.
    axes.plot([-0.9, -0.9], [-2, 2], color='mediumseagreen', linewidth=1, alpha=0.8)
    axes.plot([-0.9, 0.9], [2, 2], color='mediumseagreen', linewidth=1, alpha=0.8)
    axes.plot([0.9, 0.9], [2, -2], color='mediumseagreen', linewidth=1, alpha=0.8)
    axes.plot([0.9, -0.9], [-2, -2], color='mediumseagreen', linewidth=1, alpha=0.8)
    axes.plot([0.0, 0.0], [0.0, 2], color='mediumseagreen', linewidth=1, alpha=0.8)
    plan_cmd = np.argmax(pred_data['plan_results'][sample_token][1][0,0,0])
    plan_traj = pred_data['plan_results'][sample_token][0][plan_cmd]
    plan_traj[abs(plan_traj) < 0.01] = 0.0
    plan_traj = plan_traj.cumsum(axis=0)
    plan_traj = np.concatenate((np.zeros((1, plan_traj.shape[1])), plan_traj), axis=0)
    plan_traj = np.stack((plan_traj[:-1], plan_traj[1:]), axis=1)

    plan_vecs = None
    for i in range(plan_traj.shape[0]):
        plan_vec_i = plan_traj[i]
        x_linspace = np.linspace(plan_vec_i[0, 0], plan_vec_i[1, 0], 51)
        y_linspace = np.linspace(plan_vec_i[0, 1], plan_vec_i[1, 1], 51)
        xy = np.stack((x_linspace, y_linspace), axis=1)
        xy = np.stack((xy[:-1], xy[1:]), axis=1)
        if plan_vecs is None:
            plan_vecs = xy
        else:
            plan_vecs = np.concatenate((plan_vecs, xy), axis=0)

    cmap = 'winter'
    y = np.sin(np.linspace(1/2*np.pi, 3/2*np.pi, 301))
    colors = color_map(y[:-1], cmap)
    line_segments = LineCollection(plan_vecs, colors=colors, linewidths=1, linestyles='solid', cmap=cmap)
    axes.add_collection(line_segments)

    axes.axes.xaxis.set_ticks([])
    axes.axes.yaxis.set_ticks([])
    axes.axis('off')
    fig.set_tight_layout(True)
    fig.canvas.draw()
    plt.savefig(savepath+'/bev_pred.png', bbox_inches='tight', dpi=200)
    plt.close()

    Visualizes a sample from BEV with annotations and detection results.
    :param nusc: NuScenes object.
    :param sample_token: The nuScenes sample token.
    :param gt_boxes: Ground truth boxes grouped by sample.
    :param pred_boxes: Prediction grouped by sample.
    :param nsweeps: Number of sweeps used for lidar visualization.
    :param conf_th: The confidence threshold used to filter negatives.
    :param eval_range: Range in meters beyond which boxes are ignored.
    :param verbose: Whether to print to stdout.
    :param savepath: If given, saves the the rendering here instead of displaying.
    
tools/analysis_tools/visualization.py