#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
File name: plot_setup.py
Orig Author: Neil E Cotter
Date Created: Sat 05/14/2022 10:45 a.m. from snn_respsurfplot.py
Python Version: 3.8.8

-----------------------------------------------------------------------
def main():
    return
-----------------------------------------------------------------------
"""


#import sys

import math

import matplotlib.pyplot as plt
import numpy as np

#from snn_math import de2bi de2tri

import View_3dim_in_2dim.two_dim_view as view2D

#from snn_respsurf_include import *
import snn_respsurf_include as snni

#from syn_waveforms import syn_wave_neg_edge
from syn_waveforms import syn_wave_shape
import syn_waveforms as syn

#import snn_neuron

#from snn_math import dec2tri
#import respsurf_X_volumes as Xc
#from respsurf_Xregion_edge_intersect_pts import *
import snn_respsurf_X_region as Xi
#from respsurf_Xregion_plot import *


######################################################################
def plot_setup():
    """
    plot_setup()
    return fig_ptr, ax

    Set up plot.

    Input variables:
    
    
    

    """

    # Create figure.
    fig_ptr = plt.figure(1,figsize=(7,7))

    # Need subplot in order to make plot square.
    if square_flag == TRUE:
        ax = fig_ptr.add_subplot(111, aspect='equal')
    else
        ax = fig_ptr.add_subplot(111)

    # Coordinates in 2D image plane range from -5 to 5 in x and y.
    plt.axis([-5,5,-5,5])
    plt.title('SNN Response Surface')

    # Axis labels and tick marks.
    plt.xlabel('Omega (r/s)')
    plt.ylabel('|H(omega)|')
    #plt.text(1.5,3,'Text on Plot')
    #plt.text(2,4,'$y = x^2$')  # LateX-style text on plot.
    plt.xticks([])  # No tick marks.
    # Log spaced ticks.
    plt.xticks(math.log10(np.arange(-2, 2, step=)
    plt.yticks([])  # No tick marks.

    # Examples of other useful plot commands, for reference.
    #plt.plot([1,2],[3,4],'r-',linewidth=1.0)
    #plt.plot([1,2],[4,5],color=(0.5,0.5,0.5),linewidth=1.0)

    #plt.axes().set_aspect('equal', adjustable='datalim')
    #ax.set_aspect('equal',adjustable='box')
    #plt.axes().set_aspect('equal')
    #plt.savefig('response_surface.png')

    return fig_ptr, ax


#######################################################################
def draw_X_cubes(
        fig, ax, view1, syn_shape,
        back_face_flag, fore_face_flag):
    """
    Draw X- (or chi-) cubes for SNN response surfaces.
    That is, draw eight unit cubes with origin in the center.
    Draw faces of cubes by connecting five points (starting point = end
      point).
    Faces on the inside are shared with other cubes but are drawn twice
      for clarity of code.
    3-Dim image is projected onto 2-Dim viewing plane.
    Back faces should be drawn before plotting response surfaces, and
    fore faces should be drawn after plotting response surfaces in
    order to achieve proper layering.  (Fore faces may be drawn before
    and after response surface, if desired, in order to show a complete
    set of X-cubes initially.)
    

Modify to find faces of (one) X-region by offsetting from center pt of
X-region by +- 1/2 in each t_i axis direction.  Then order the center
pts of faces by distance from viewer.  Furthest three faces are back
faces.  Closest three faces are fore faces.

    Inputs:
        fig = (ptr to figure)
        ax = (ptr to axes of figure)
        view1 =  (class ViewPt see two_dim_view.py) 3D viewpoint
            and focal point
        syn_shape = (dictionary syn_wave_shape see
            syn_waveforms.py) syanpse response waveform shape
        back_face_flag = (True/False) draw the faces of X-cube farthest
            from viewer
        fore_face_flag = (True/False) draw the faces of X-cube closest
            to viewer
    
    Outputs:
        no values, draws boxes around X-cubes (i.e., X-regions with all
            synapses active
    """
    
    # Draw the eight X-cubes.
    # Each cube has six faces = 3-dims * 2 faces.
    # Start with cube farthest from usual view pt.
    # That is, X = (-1,-1,-1).
    neg_X_cube_edge = syn.syn_wave_neg_edge[syn_shape]
    #print("neg_X_cube_edge = ")
    #print(neg_X_cube_edge)
    
    # Loop over t1 values.
    for t1_index in [neg_X_cube_edge,1.0]:
        # Loop over t2 values.
        #print("t1_index = ")
        #print(t1_index)
        for t2_index in [neg_X_cube_edge,1.0]:
            # Loop over t3 values.
            for t3_index in [neg_X_cube_edge,1.0]:
    
                # Set RGB color so cubes closer to X = (1,1,1)
                #  are darker.
                RGB_color = ((1 - 0.08/(-neg_X_cube_edge)
                  * (t1_index + t2_index + t3_index))
                  * np.array([0.7, 0.7, 0.7]))
    
                # Loop over two faces of each dimension.
                for dim1 in t1_index * np.array([0,1]):
    
                    # Calculate 4 corner points of face.
                    #  Repeat 1st pt to close square.
                    Projected_points = np.array([
                                                [dim1,0,0],
                                                [dim1,0,t3_index],
                                                [dim1,t2_index,
                                                 t3_index],
                                                [dim1,t2_index,0],
                                                [dim1,0,0]])
    
                    #print("Projected_points 1st = \n")
                    #print(Projected_points)
    
                    # Project from 3dim to 2dim view.
                    V1 = view2D.proj_to_2D(view1, Projected_points)
    
                    # Plot the 3dim object as 2dim image
                    plt.plot(V1[:,0], V1[:,1],
                             color=RGB_color,linewidth=0.5)
    
                for dim2 in t2_index * np.array([0,1]):
    
                    # Calculate 4 corner points of face.
                    # Repeat 1st pt to close square.
                    Projected_points = np.array([
                                                [0,dim2,0],
                                                [0,dim2,t3_index],
                                                [t1_index,dim2,
                                                 t3_index],
                                                [t1_index,dim2,0],
                                                [0,dim2,0]])
    
                    #print("Projected_points 2nd = \n")
                    #print(Projected_points)
    
                    # Project from 3dim to 2dim view.
                    V1 = view2D.proj_to_2D(view1, Projected_points)
    
                    # Plot the 3dim object as 2dim image
                    plt.plot(V1[:,0], V1[:,1],
                             color=RGB_color, linewidth=0.5)
    
                for dim3 in t3_index * np.array([0,1]):
                    # Calculate 4 corner points of face.
                    # Repeat 1st pt to close square.
                    Projected_points = np.array([
                                                [0,0,dim3],
                                                [0,t2_index,dim3],
                                                [t1_index,t2_index,
                                                 dim3],
                                                [t1_index,0,dim3],
                                                [0,0,dim3]])
                    #print("Projected_points 3rd = \n")
                    #print(Projected_points)
    
                    # Project from 3dim to 2dim view.
                    V1 = view2D.proj_to_2D(view1, Projected_points)
    
                    # Plot the 3dim object as 2dim image
                    plt.plot(V1[:,0], V1[:,1],
                             color=RGB_color,linewidth=0.5)

    return


#######################################################################
def draw_respsurf_axes( \
        fig, ax, view1, syn_shape, \
        t1_axis_flag, t2_axis_flag, t3_axis_flag):
    """
    draw_RS_axes(syn_shape, neuron_A, view1, fig, ax)
    Draw axes for synapse firing times t1, t2, and t3 on 3D Response
        Surface plot.

    Inputs:
        fig = (ptr to figure)
        ax = (ptr to axes of figure)
        view1 = (class ViewPt see two_dim_view.py) 3D viewpoint and
            focal point
        syn_shape = (dictionary syn_wave_shape see
            syn_waveforms.py) syanpse response waveform shape
        t1_axis_flag = (True/False) draw t1 axis
        t2_axis_flag = (True/False) draw t2 axis
        t3_axis_flag = (True/False) draw t3 axis
    
    Outputs:
        no values, draws custom axes on figure
    """

    # For clarity, axes are drawn one at a time (instead of in a loop).
    ##--- t1 axis ---##
    if t1_axis_flag == True:
        # Set endpoints of axis in 3D.
        if syn_shape == syn_wave_shape['SYN_TRIANGULAR_SYMMETRIC']:
            t1_axis = np.array([2.0,0.0,0.0])
        else:
            # Longer axis needed since cubes extend to -2 in 3D for 
            #   realistic syn shapes.
            t1_axis = np.array([2.5,0.0,0.0])

        # Draw the line for the t1 axis in blue.
        Projected_points = np.array([[0.0,0.0,0.0],t1_axis])
    
        # Blue color for t1 axis.
        blue = np.array([0.0,0.0,1.0])
    
        # Project from 3dim to 2dim view.
        V1 = view2D.proj_to_2D(view1, Projected_points)
    
        # Plot the t1 axis.
        ax.plot(V1[:,0], V1[:,1], color=blue,linewidth=1.0)
    
        # Compute position of dot at end of axis.
        t1_dot_pos = t1_axis
    
        # Compute position of dot in 2-Dim.
        V1 = view2D.proj_to_2D(view1, [t1_dot_pos])
    
        # Put dot on plot.
        ax.add_patch(plt.Circle((V1[0,0], V1[0,1]), radius=0.015,
                     color=blue))
    
        # Compute t1 axis label position in 3-Dim.
        t1_label_pos = t1_axis + np.array([0.25,0.0,0.0])
    
        # Compute position of axis label in 2-Dim.
        V1 = view2D.proj_to_2D(view1, [t1_label_pos])
    
        # Put text label on plot.
        ax.text(V1[0,0], V1[0,1], 't1',
          color=blue, fontfamily='Times New Roman', fontsize=14.0)

    ##--- t2 axis ---##
    if t2_axis_flag == True:
        # Set endpoints of axis in 3D.
        if syn_shape == syn_wave_shape['SYN_TRIANGULAR_SYMMETRIC']:
            t2_axis = np.array([0.0,2.0,0.0])
        else:
            # Longer axis needed since cubes extend to -2 in 3D for 
            #   realistic syn shapes.
            t2_axis = np.array([0.0,2.5,0.0])

        # Draw the line for the t2 axis in blue.
        Projected_points = np.array([[0.0,0.0,0.0],t2_axis])
    
        # Green color for t2 axis.
        green = np.array([0.0,0.75,0.0])
    
        # Project from 3dim to 2dim view.
        V1 = view2D.proj_to_2D(view1, Projected_points)
    
        # Plot the t2 axis.
        ax.plot(V1[:,0], V1[:,1], color=green,linewidth=1.0)
    
        # Compute position of dot at end of axis.
        t2_dot_pos = t2_axis
    
        # Compute position of dot in 2-Dim.
        V1 = view2D.proj_to_2D(view1, [t2_dot_pos])
    
        # Put dot on plot.
        ax.add_patch(plt.Circle((V1[0,0], V1[0,1]), radius=0.015,
                     color=green))
    
        # Compute t2 axis label position in 3-Dim.
        t2_label_pos = t2_axis + np.array([0.0,0.2,0.0])
    
        # Compute position of axis label in 2-Dim.
        V1 = view2D.proj_to_2D(view1, [t2_label_pos])
    
        # Put text label on plot.
        ax.text(V1[0,0], V1[0,1], 't2',
          color=green, fontfamily='Times New Roman', fontsize=14.0,
          horizontalalignment='center')

    ##--- t3 axis ---##
    if t3_axis_flag == True:
        # Set endpoints of axis in 3D.
        if syn_shape == syn_wave_shape['SYN_TRIANGULAR_SYMMETRIC']:
            t3_axis = np.array([0.0,0.0,2.5])
        else:
            # Longer axis needed since cubes extend to -2 in 3D for 
            #   realistic syn shapes.
            t3_axis = np.array([0.0,0.0,2.7])

        # Draw the line for the t3 axis in blue.
        Projected_points = np.array([[0.0,0.0,0.0],t3_axis])
    
        # Red color for t3 axis.
        red = np.array([1.0,0.0,0.0])
    
        # Project from 3dim to 2dim view.
        V1 = view2D.proj_to_2D(view1, Projected_points)
    
        # Plot the t3 axis.
        ax.plot(V1[:,0], V1[:,1], color=red,linewidth=1.0)
    
        # Compute position of dot at end of axis.
        t3_dot_pos = t3_axis
    
        # Compute position of dot in 2-Dim.
        V1 = view2D.proj_to_2D(view1, [t3_dot_pos])
    
        # Put dot on plot.
        ax.add_patch(plt.Circle((V1[0,0], V1[0,1]), radius=0.015, \
                     color=red))
    
        # Compute t3 axis label position in 3-Dim.
        t3_label_pos = t3_axis + np.array([0.0,0.0,0.1])
    
        # Compute position of axis label in 2-Dim.
        V1 = view2D.proj_to_2D(view1, [t3_label_pos])
    
        # Put text label on plot.
        ax.text(V1[0,0], V1[0,1], 't3', \
          color=red, fontfamily='Times New Roman', fontsize=14.0, \
          horizontalalignment='center')

    return



#######################################################################
def respsurf_line_segment_categorize( \
        view1, plot_params, syn_shape, X_vec, first_edge_pt, \
        second_edge_pt, debug_flag=False):
    """
    return seg_type, plot_for_compact

    respsurf_line_segment_categorize(syn_shape, X_vec, first_edge_pt, \
        second_edge_pt)
    return seg_type3D, seg_type2D, seg_type1D, outer_face_flag, \
        outer_edge_flag
    
    Determines what type of line segment is being plotted: part of 3D
    facet, part 2D extended strips, part of 1D extended walls, part of
    2D slants on outer faces of X-cubes, part of 1D extended in 2D
    straights, or part of 1D points on outer edges of X-cubes.

    Inputs: (set in earlier script files)
        syn_shape = # specifying post synaptic potential waveform shape
                    being used (see Syn_def_waveform_number.m)
        X_vec = (np.array int horiz 1xN vector) of +1, 0, or -1 values
        first_edge_pt = (np.array x3 horiz) 1st endpoint of segment
            to plot, must lie on an outer edge of a X-region
        second_edge_pt = (np.array x3 horiz) 2nd endpoint of segment
            to plot, must lie on an outer edge of a X-region
            Values in rows.  Set by:
            respsurf_Xregion_edge_intersect_pts().
        n_slices = 
        distance_between_line_pts = approx distance by which points on
            a line located on a face are separated from each other.
            Set in programs such as SNN__3_D_Resp_Surf_Realistic_Plot.m
        plot parameters = 
    
    Output:
        seg_type = (scalar int see dictionary: plot_segment_type) Line
            segment type: number of active synapses and dimension of
            plot type (3D surface, 2D lines, 1D points).
    """


    #-------------------------------------------------------------#
    # Categorize the line segment being plotted.
    #-------------------------------------------------------------#
    # Determine dimensionality of line segment based on X-region
    #   and how many t_i are on outer face or edge of X-region.

    if debug_flag == True:
        print('Start of respsurf_line_segment_categorize()')

    # Default values.
    seg_type = snni.plot_segment_type['VOID']
    back_fore_pos = snni.plot_segment_pos['BACK_XREGION']

    # Return empty, Back Region, and not compact if input is empty
    #   vector.

    if first_edge_pt.size == 0:
        return seg_type, back_fore_pos

    # Determine the number of active synapses in X-region.
    dim_X_region_active = np.sum(X_vec != 0)

    # Compute segment midpoint for foreground or background
    #   determination later on.
    #mid_point = (first_edge_pt + second_edge_pt) * 0.5

    # Default flag values for compact plot.  Not used.
    #outer_face_flag = False
    #outer_edge_flag = False

    # Determine how many t_i for X=0 are at positive or negative X
    #   edge.  Both endpts of line segment must have same value
    #   that is at positive or negative X edge.
    num_t_i_at_pos_edge_for_X_eq_0 = 0
    num_t_i_at_edge_for_X_eq_0 = 0
    for index_X in range(3):
        if debug_flag == True:
            print(index_X)
            print(X_vec)
            print(X_vec[index_X])
        if X_vec[index_X] == 0:
            if first_edge_pt[index_X] == second_edge_pt[index_X]:
                if first_edge_pt[index_X] == \
                        syn.syn_wave_pos_edge[syn_shape]:
                    num_t_i_at_pos_edge_for_X_eq_0 += 1
                    num_t_i_at_edge_for_X_eq_0 += 1

                if first_edge_pt[index_X] == \
                        syn.syn_wave_neg_edge[syn_shape]:
                    num_t_i_at_edge_for_X_eq_0 += 1

    if debug_flag == True:
        print('After counting t_i coords pos or neg X edge')
        print(' X_vec = ')
        print(X_vec)
        print(' first_edge_pt = ')
        print(first_edge_pt)
        print(' second_edge_pt = ')
        print(second_edge_pt)
        print(' num_t_i_at_edge_for_X_eq_0 = ')
        print(num_t_i_at_edge_for_X_eq_0)

    # Initialize segment type to default value.
    seg_type = snni.plot_segment_type['VOID']
    plot_if_compact = False

    # 3-syn: Facet if all three X are nonzero.
    if dim_X_region_active == 3:  # X-region is Cube.
        seg_type = snni.plot_segment_type['FACET']
        plot_if_compact = True

    # 2-syn: Slant or Strip if two X are nonzero.
    elif dim_X_region_active == 2:  # X-region is Tube.
        # Slant if t_i for X=0 is on face of X-region shared with
        #   an X-cube.
        seg_type = snni.plot_segment_type['STRIP']
        if num_t_i_at_edge_for_X_eq_0 == 1:
            seg_type = snni.plot_segment_type['SLANT']
            if num_t_i_at_pos_edge_for_X_eq_0 == 1:
                plot_if_compact = True

    # 1-syn: Point or Straight or Wall if one X is nonzero.
    elif dim_X_region_active == 1:  # X-region is Slab.
        # Point if t_i for X=0 is on edge of X-region shared with
        #   X-cube.
        # Straight if t_i for X=0 is on face of X-region extending
        #   from X-cube.
        seg_type = snni.plot_segment_type['WALL']
        if num_t_i_at_edge_for_X_eq_0 == 1:
            seg_type = snni.plot_segment_type['STRAIGHT']
            # If both segment points the same, it is a point.
            if np.all(first_edge_pt == second_edge_pt):
                seg_type = snni.plot_segment_type['POINT']
                plot_if_compact = True

    return seg_type, plot_if_compact



#######################################################################
def respsurf_line_segment_plot( \
            fig, ax, view1, plot_params, syn_shape, N, T, w_vec, \
            X_vec, first_edge_pt, second_edge_pt, seg_type, \
            plot_compact, outline_flag=False, debug_flag=False):
    """
    plot_rs_line_segment(plot_params, plot_flags, syn_shape, X_vec, T, \
        w_vec, first_edge_pt, second_edge_pt)
    return
    
    This function plots a single line on the response surfaces for a
    given realistic synaptic shape by creating small line segments
    connecting endpoints passed in as pairs of points in 3-D space.
    
    Inputs:
        fig = (ptr to figure)
        ax = (ptr to axes of figure)
        view1 = (class ViewPt see two_dim_view.py) 3D viewpoint and
            focal point
        plot_params = (class RS_PlotParams) 3D viewpoint and\
            focal point
        syn_shape = (dictionary syn_wave_shape see
            syn_waveforms.py) syanpse response waveform shape
        N = (int scalar) number of synapses for neuron
        T = (float scalar) neuron threshold
        w_vec = (np.array float 1xN) neruon's synaptic weights
        X_vec = (np.array int horiz 1xN vector) of +1, 0, or -1 values
            for X-region of synapse states
        first_edge_pt = (np.array float 1xN) one end of line segment
        second_edge_pt = (np.array float 1xN) other end of line segment
        seg_type = (dictionary plot_segment_type see
            snn_respsurf_include.py)
        plot_compact = (True/False) plot only compact plot elements
        outline_flag=False = (True/False) draw white outline for segment
            rather than segment itself
        debug_flag=False = (True/False) turn on verbose output
    Output:
         -  No return value.  Just plots a line segment on the response
            surface for a given realistic synaptic waveform shape in
            one X-region.
    
    Since the endpoints passed into this function all lie in one
    X-region, the line segments connecting them must lie in the
    same X-region.  The endpoints for the linear synaptic responses may
    also be distorted via inverse synaptic response waveforms to obtain
    the response surfaces for realistic, nonlinear synapse responses.
    Note that the nonlinear response surfaces will lie in the same
    X-region as the linear symmetric response.  (The X-region may
    become larger, but the X-vector will be the same.)
    
    To accomplish the distortion of the response surface, the procedure
    is as follows.  For each segment endpoint, the activity of each
    linear synapse is equated with the activity of the linear
    symmetric synapse response, and the firing time of the realistic
    synapse needed to have that activity is determined by an inverse
    synapse waveform function.
    
    The result is a modified firing time for the realistic synapse
    shape.  These modified firing times are plotted as endpoints of
    short line segments, as in the linear case.  The result is response
    surface for the realistic synapse shape.
    
    The slope of the total activity is checked and must be positive at
    time zero unless ignore_neg_slope_flag is set.  If total activity
    is negative, that point is skipped, unless unless
    ignore_neg_slope_flag is set.
    
    Calling program must order segments by depth of view for segments
    if plotting from back to front desired.
    """


    #-----------------------------------------------------------------#
    # Return immediately if this segment will not be plotted.
    plot_seg_flag = False

    if seg_type == snni.plot_segment_type['FACET'] \
            and plot_params.facets_3D_flag == True:
        plot_seg_flag = True

    if seg_type == snni.plot_segment_type['STRIP'] \
            and plot_params.strips_3D_flag == True \
            and plot_compact == False:
        plot_seg_flag = True

    if seg_type == snni.plot_segment_type['WALL'] \
            and plot_params.walls_3D_flag == True \
            and plot_compact == False:
        plot_seg_flag = True

    if seg_type == snni.plot_segment_type['SLANT'] \
            and plot_params.slants_2D_flag == True:
        plot_seg_flag = True

    if seg_type == snni.plot_segment_type['STRAIGHT'] \
            and plot_params.straights_2D_flag == True \
            and plot_compact == False:
        plot_seg_flag = True

    if seg_type == snni.plot_segment_type['POINT'] \
            and plot_params.points_1D_flag == True:
        plot_seg_flag = True

    if plot_seg_flag == False:
        return


    #-----------------------------------------------------------------#
    # If single point on edge, create t_mat with one entry.
    if seg_type == snni.plot_segment_type['POINT']:
        # If edge intersect is single point on outside edge of
        #   X-cubes, the "segment" is one duplicated point.
        num_slices = 2
        t_mat = np.array([first_edge_pt, second_edge_pt])
    else:
        # Create small line segments.
        #   Create an array of points equally spaced on the line
        #   between the edge points.
    
        distance_between_edge_pts = \
            np.sqrt(np.sum((first_edge_pt - second_edge_pt)**2))
    
        if seg_type == snni.plot_segment_type['POINT']:
            # If edge intersect is single point on outside edge of
            #   X-cubes, the "segment" is one duplicated point, so use
            #   two "slices".
            num_slices = 2
        else:
            # Use an integer number of points with points located at
            #   both ends of the line, and space them as close as
            #   possible to the value of distance_between_line_pts.
            # Use at least two points so short lines still plot.
            num_slices = np.floor(
                    1 + distance_between_edge_pts
                        * plot_params.n_slices_last_dim)
    
            num_slices = num_slices.astype(int)
    
        t_mat = np.linspace( \
                first_edge_pt, second_edge_pt, \
                num=num_slices)

    if debug_flag == True:
        print('t_mat = ')
        print(t_mat)

    #-----------------------------------------------------------------#
    # Calculate firing times for realistic synapses.

    #   Initialize arrays to hold realistic synapse firing times.
    r_mat = np.zeros((num_slices,N))

    # Set firing times to impossible values initially.
    t_realistic_mat = np.ones((num_slices,N)) * -100.0

    # Set synapses to inactive states.
    activity_slope = np.zeros(num_slices)

    # Start with a straight line between the endpoints computed for
    #   triangular symmetric synapse shape.  Chop the line between the
    #   endpoints on the outer edges of X-region into small line
    #   segments (or duplicate single pt for 1-dim solutions).
    # Distort the endpoints of the short line segments if nonlinear
    #   synapse response is used.
    for index_t_vec, t_vec_linear in enumerate(t_mat):
        # Calculate the activity of triangular symmetric synapse.
        r_vec = syn.syn_waveform( \
                syn_wave_shape['SYN_TRIANGULAR_SYMMETRIC'], \
                -t_vec_linear)
        r_mat[index_t_vec, :] = r_vec.flatten()

        # Note: total activity equal T at this point.

        # Transform to realistic nonlinear synapse response
        #   firing times by moving synapse firing time to get same
        #   activity at t = 0 as with triangular symmetric synapse.
        t_realistic_vec = -syn.syn_inverse_waveform( \
                syn_shape, r_vec, -t_vec_linear)
        t_realistic_vec = t_realistic_vec.flatten()

        # Change nan values to non-inverse t value.
        for index_t_r_value in range(3):
            if np.isnan(t_realistic_vec[index_t_r_value]):
                t_realistic_vec[index_t_r_value] = \
                        t_vec_linear[index_t_r_value]

        # Put result in matrix.
        t_realistic_mat[index_t_vec, :] = \
                t_realistic_vec

        # Calculate the total activity slopes at threshold.
        activity_slope[index_t_vec] = \
                np.sum(syn.syn_slope(syn_shape, -t_realistic_vec) \
                * w_vec)


    if debug_flag == True:
        print('t_realistic_mat = ')
        print(t_realistic_mat)


    #-----------------------------------------------------------------#
    # Step through the realistic points on the small line segments.
    for index_t_realistic_vec, t_realistic_vec in \
            enumerate(t_realistic_mat):

        # Since points are used in pairs, skip last point
        #   since it has no successor.
        if index_t_realistic_vec == np.size(t_realistic_mat, \
                axis=0) - 1:
            continue

        # Extract two points for a segment from array.
        t_realistic_seg = \
            t_realistic_mat[index_t_realistic_vec: \
                    index_t_realistic_vec+2,:]

        # Line segments are only completed if both ends are
        #   valid.  Assume endpts are valid until proven
        #   otherwise.

        # Delete segments with negative total synaptic activity
        #   unless flag set.
        if plot_params.ignore_neg_slope_flag == False \
            and (activity_slope[index_t_realistic_vec] <= 0 \
                or activity_slope[index_t_realistic_vec+1] <= 0):

            # Step to the next small plot segment.
            continue

        # Process point only if not special case of
        #   alpha function synapse and t_i too negative.
        # Triangular symmetric t_i = -0.8 gives crit damped t_i
        #   approx equal to -3
        if syn_shape == syn_wave_shape['SYN_ALPHA_FUNC']:
            if np.any(t_realistic_seg < -0.8):

                # Step to the next small plot segment.
                continue

        #-------------------------------------------------------------#
        # Calculate color for short line segment
        #-------------------------------------------------------------#
        # Calculate normalized activity for this pt.  Needed?
        #normed_activity_vec = np.sum(np.absolute(w_vec) * r_vec \
        #    / np.amax(np.absolute(w_vec)))

        # Find negative and positive edge of plot segment for
        #   color calcs.
        neg_X_cube_edge = syn.syn_wave_neg_edge[syn_shape]
        pos_X_cube_edge = syn.syn_wave_pos_edge[syn_shape]

        # Find midpoint of plot segment for color calcs.
        rs_seg_mid_pt = np.sum(t_realistic_seg, axis=0)/2.0;

        seg_RGB_color  = \
            rs_color(neg_X_cube_edge, rs_seg_mid_pt)

        ########################################################
        # Darken segment if flag set and we are looking at
        #   backside of response Surface.  Move slightly
        #   closer to viewpoint on line from viewpoint to
        #   segment and see if neuron activity > Threshold,
        #   meaning we moved closer to max activity, which
        #   occurs when all synapses fire at time zero.
        if plot_params.darken_inside_rs_colors_flag == True:
            # Find pt slightly closer to viewpoint in direction
            #   from viewpoint to first endpt.
            nudged_t_vec = (1 - 1e-6) * t_realistic_seg[0,:] \
                + 1e-6 * view1.view_point;
            # Darken segment if nudged t_vec gives activity > 0.
            if np.sum(syn.syn_waveform(syn_shape, \
                - nudged_t_vec[X_vec != 0]) \
                * w_vec[X_vec != 0]) > T:
                
                # Darken segment.
                seg_RGB_color = np.array(seg_RGB_color)/1.75

        #############################################################
        # Outline 3D Response Surface (RSs) in black if flag set.
        # Do last because it supercedes other special cases.
        if plot_params.outline_3D_flag == True:
            # Check for a dimension where entries of both ends of
            #   line segment = neg_X_edge, or 0, or pos_X_edge, which
            #   means segment is on a face of the X-region.
            # Check each dimension.
            for RS_dim_index in range(3):
                # Get the line segment endpt coordinates of nth
                #   (RS_dim_index) dim.
                if debug_flag == True:
                    print('RS_dim_index = ')
                    print(RS_dim_index)
                    print('left_end = ')
                    print(t_mat[index_t_realistic_vec,:])
                    print('right_end = ')
                    print(t_mat[index_t_realistic_vec+1,:])

                left_end_coord = \
                    t_mat[index_t_realistic_vec,RS_dim_index]
                right_end_coord = \
                    t_mat[index_t_realistic_vec+1,RS_dim_index]

                if np.isclose(left_end_coord,0.0) \
                        and np.isclose(right_end_coord,0.0):
                    if debug_flag == True:
                        print('both end coords approx = 0')
                        print('RS_dim_index = ')
                        print(RS_dim_index)
                        print('left_end_coord = ')
                        print(left_end_coord)
                        print('right_end_coord = ')
                        print(right_end_coord)
                if left_end_coord == right_end_coord:
                    if np.isclose(left_end_coord,neg_X_cube_edge) \
                            or np.isclose(left_end_coord,0) \
                            or np.isclose(left_end_coord, \
                                          pos_X_cube_edge):
                        if debug_flag == True:
                            print(' using black')
                            print('left_end_coord = ')
                            print(left_end_coord)
                            print('right_end_coord = ')
                            print(right_end_coord)
                         # Use black to outline RSs.
                        seg_RGB_color = np.array([0.0, 0.0, 0.0])
                        # Exit loop after any coordinate found at
                        #   X-cube edge, since segment is already black.
                        break


        #-------------------------------------------------------------#
        # Project from 3dim to 2dim view.
        #-------------------------------------------------------------#
        V1 = view2D.proj_to_2D(view1, t_realistic_seg)

        #-------------------------------------------------------------#
        # Plot line segment or not, according to what to plot.
        #-------------------------------------------------------------#
        if debug_flag == True:
            print('seg_type = ')
            print(seg_type)

        ###############################################################
        # 3D plot types:
        # FACET if 3D and all three X are nonzero
        if seg_type == snni.plot_segment_type['FACET'] \
            and plot_params.facets_3D_flag == True:

            plt.plot(V1[:,0], V1[:,1], \
                color=seg_RGB_color,linewidth=1.0)

        # STRIP if 3D and two X are nonzero
        #        or SLANT (2D and two X are nonzero)
        if plot_params.strips_3D_flag == True:
            if (seg_type == snni.plot_segment_type['STRIP'] \
                    or seg_type == snni.plot_segment_type['SLANT']):

                plt.plot(V1[:,0], V1[:,1], \
                    color=seg_RGB_color,linewidth=1.0)

        # WALL if 1D and one X is nonzero
        #        or STRAIGHT (2D and two X are nonzero)
        #        or POINT (1D and two X are nonzero)
        if plot_params.walls_3D_flag == True:
            if (seg_type == snni.plot_segment_type['WALL'] \
                    or seg_type == snni.plot_segment_type['STRAIGHT'] \
                    or seg_type == snni.plot_segment_type['POINT']):

                plt.plot(V1[:,0], V1[:,1], \
                    color=seg_RGB_color,linewidth=1.0)

        ###############################################################
        # 2D plot types:
        # SLANT if 2D and two X are nonzero
        #   AND
        # t_i for the X = 0 is at positive or negative X edge
        if plot_params.slants_2D_flag == True:
            if seg_type == snni.plot_segment_type['SLANT']:

                # Outline slants in white if flag set.  Because wider
                #   white line segment is slightly longer than solid
                #   line segment for slant, entire line of
                #   white outline must be completed before plotting
                #   slant to avoid dashed line appearance.
                if outline_flag == True:

                    plt.plot( \
                            V1[:,0], V1[:,1], \
                            color=snni.RGB_colors['WHITE'], \
                            linewidth=5.0)

                # Plot all thick line segments for slant only after all
                #   outline segments plotted to avoid getting dashed
                #   line for slant.
                else:
                    plt.plot( \
                            V1[:,0], V1[:,1], \
                            color=seg_RGB_color,linewidth=3.0)

        # STRAIGHT if one X is nonzero
        #   AND
        #  two t_i's for X = 0 is at positive or negative X edge
        if plot_params.straights_2D_flag == True:
            if seg_type == snni.plot_segment_type['STRAIGHT']:

                # Outline sraights in white if flag set.  Because wider
                #   white line segment is slightly longer than solid
                #   line segment for straight, entire line of
                #   white outline must be completed before plotting
                #   straight to avoid dashed line appearance.
                if outline_flag == True:

                    plt.plot( \
                            V1[:,0], V1[:,1], \
                            color=snni.RGB_colors['WHITE'], \
                            linewidth=5.0)

                # Plot all thick line segments for straight only after
                #   all outline segments plotted to avoid getting
                #   dashed line for straight.
                else:
                    plt.plot( \
                            V1[:,0], V1[:,1], \
                            color=seg_RGB_color,linewidth=3.0)

        ###############################################################
        # 1D plot types:
        # POINT if one X is nonzero
        #   and
        # two of the t_i for X's = 0 are at positive or negative X edge
        if plot_params.points_1D_flag == True:
            if seg_type == snni.plot_segment_type['POINT']:
                print('plot pt on edge')

                # Plot small circle, normal to edge, around where point
                #   would be located on outer edge of X-cube.

                # For compact plot, only plot points on X = +1 edges.
                t_realistic_pt = t_realistic_mat[index_t_realistic_vec]
                num_plus_one_X_vals = np.size(t_realistic_pt == 1.0)
                #num_neg_one_X_vals = np.size(t_realistic_pt == -1.0)

                # Only plot if point is on appropriate edge of X-cubes.
                if plot_params.compact_plot_flag == False \
                        or num_plus_one_X_vals >= 2:

                    # Set the first point on the circle.
                    normal_dims = np.argwhere(t_realistic_pt**2 == 1.0)
    
                    prev_circle_plot_pt = t_realistic_pt
                    prev_circle_plot_pt[normal_dims] = \
                            snni.one_dim_circle_radius
    
                    # Step around the circle.
                    # Need to define one_dim_pt?
                    angle_inc = 2 * np.pi / 16.0
                    for one_dim_circle_angle in range(angle_inc, \
                        16*angle_inc, angle_inc):
    
                        first_X_dir_offset = \
                                snni.one_dim_circle_radius * \
                                math.cos(one_dim_circle_angle)
                        second_X_dir_offset = \
                                snni.one_dim_circle_radius * \
                                math.sin(one_dim_circle_angle)
    
                        # Add offsets to X coords that are nonzero.
                        circle_plot_pt = t_realistic_pt
                        circle_plot_pt[normal_dims] = \
                                [first_X_dir_offset, \
                                 second_X_dir_offset]
    
                        # Create next segment of circuit.
                        circle_points = np.vstack( \
                                (prev_circle_plot_pt, \
                                circle_plot_pt))
    
                        # Project from 3dim to 2dim view.
                        V1 = view2D.proj_to_2D(view1, circle_points)
    
                        # Find the RGB color values for center point.
                        circle_RGB_color  = rs_color( \
                                neg_X_cube_edge, prev_circle_plot_pt, \
                                False)
    
                        # Plot segment of circle.
                        plt.plot( \
                                 V1[:,0], V1[:,1], \
                                color=circle_RGB_color,linewidth=2.0)
                            
                        prev_circle_plot_pt = circle_plot_pt

    return



#######################################################################
def resp_surf_Xregion_plot( \
        fig, ax, view1, plot_params, syn_shape, \
        X_vec, N, T, w_vec, edge_intersect_pts, debug_flag=False):
    """
    resp_surf_facet_plot(plot_params, plot_flags, syn_shape, X_vec, T, \
    w_vec, edge_intersect_pts)
    return

    This function plots the response surfaces for a given realistic
    synaptic shape by plotting line segments passed into it as
    pairs of points in 3-D space.

    Inputs:
    Inputs:
        fig = (ptr to figure)
        ax = (ptr to axes of figure)
        view1 = (class ViewPt see two_dim_view.py) 3D viewpoint and
            focal point
        plot_params = (class RS_PlotParams) 3D viewpoint and\
            focal point
        syn_shape = (dictionary syn_wave_shape see
            syn_waveforms.py) syanpse response waveform shape
        N = (int scalar) number of synapses for neuron
        T = (float scalar) neuron threshold
        w_vec = (np.array float 1xN) neruon's synaptic weights
        X_vec = (np.array int horiz 1xN vector) of +1, 0, or -1 values
            for X-region of synapse states
        first_edge_pt = (np.array float 1xN) one end of line segment
        second_edge_pt = (np.array float 1xN) other end of line segment
        seg_type = (dictionary plot_segment_type see
            snn_respsurf_include.py)
        plot_compact = (True/False) plot only compact plot elements
        outline_flag=False = (True/False) draw white outline for segment
            rather than segment itself
        debug_flag=False = (True/False) turn on verbose output
        plot_params = (class RS_PlotParams)
        syn_shape = (int dict syn_wave_shape see syn_waveforms.py) \
            # specifying post synaptic potential waveform shape
        X_vec = (np.array int horiz 1xN vector) of +1, 0, or -1 values
            Specifies which synaptic responses are rising, inactive, \
            or falling at time t=0 when Threshold is reached
        neuronA = (class SpikingNeuron see snn_neuron.py) number of
            synaptic wts, threshold, synaptic wts, and synaptic delays
            for one neuron
?        X_edge_intersect_pts = [subset_X_vec, subset_t_i_vec]
            Values in rows.  Set by:
            resp_surf_Xregion_edge_intersect_pts().
        n_slices = 
        distance_between_line_pts = approx distance by which points on
            a line located on a face are separated from each other.
            Set in programs such as SNN__3_D_Resp_Surf_Realistic_Plot.m
        plot parameters = 
    Output:
        Plots the response surfaces for a given realistic synaptic
        waveform shape in one X-region.

    This function plots line segments that form a mesh plot for a
    linear or nonlinear synapse response surface in one X-region
    (chi-region).  The line segments are plotted in small segments so
    color gradations encoding t_i values may be embedded in the colors
    of the small segments.  Using small segments creates an impression
    of continuous color changes.
    
    Since the endpoints passed into this function all lie in one
    X-region, the line segments connecting them must lie in the
    same X-region.  The endpoints for the linear synaptic responses may
    also be distorted via inverse synaptic response waveforms to obtain
    the response surfaces for realistic, nonlinear synapse responses.
    Note that the nonlinear response surfaces will lie in the same
    X-region as the linear symmetric response.  (The X-region may
    become larger, but the X-vector will be the same.)"""


    # Return empty if input is empty.
    if edge_intersect_pts.size == 0:
        segment_endpts1 = np.empty(0)
        segment_endpts2 = np.empty(0)
        return segment_endpts1, segment_endpts2

    ##################################################################
    # Processing is for syn_shape = SYN_TRIANGULAR_SYMMETRIC until
    #   waveform shape is warped by inverse functions in
    #   respsurf_line_segment_plot() at the very end
    ##################################################################

    # Extract the endpoints of line segments into two arrays.
    nrows, ncols = np.shape(edge_intersect_pts)
    new_nrows = nrows/2
    new_nrows = int(new_nrows)

    # Initialize result arrays.
    first_edge_pts = np.zeros((new_nrows, ncols))
    second_edge_pts = np.zeros((new_nrows, ncols))

    # Step through edge_intersect_pts to split them up in pairs.
    for new_index in range(new_nrows):
        first_edge_pts[new_index,:] = \
                edge_intersect_pts[2*new_index,:]

        second_edge_pts[new_index,:] = \
                edge_intersect_pts[2*new_index+1,:]

    if debug_flag == True:
        print('resp_surf_Xregion_plot() after splitting pt pairs')
        print('first_edge_pts = ')
        print(first_edge_pts)
        print('second_edge_pts = ')
        print(second_edge_pts)

    # Compute segment midpoints for distance calc.
    mid_points = (first_edge_pts + second_edge_pts) * 0.5

    # Calculate distances from line segments to view point.
    seg_dists = view2D.dist_to_viewpt(view1, mid_points)
    if debug_flag == True:
        print('resp_surf_Xregion_plot() after sort')
        print('seg_dists = ')
        print(seg_dists)

    # Sort the line segments by distance from view point.
    sorted_indices = np.flip(np.argsort(seg_dists))
    sorted_first_edge_pts = first_edge_pts[sorted_indices,:]
    sorted_second_edge_pts = second_edge_pts[sorted_indices,:]
    sorted_mid_points = mid_points[sorted_indices,:]
    if debug_flag == True:
        print('resp_surf_Xregion_plot() after sort')
        print('sorted_indices = ')
        print(sorted_indices)
        print('sorted_first_edge_pts = ')
        print(sorted_first_edge_pts)
        print('sorted_second_edge_pts = ')
        print(sorted_second_edge_pts)
        print('sorted_mid_points = ')
        print(sorted_mid_points)

    # Categorize the line segments.
    seg_types = np.zeros(new_nrows)
    plot_for_compacts = np.zeros(new_nrows)
    for seg_index in range(new_nrows):
        seg_type, plot_for_compact,  = \
                    respsurf_line_segment_categorize( \
                    view1, plot_params, syn_shape, X_vec, \
                    sorted_first_edge_pts[seg_index,:], \
                    sorted_second_edge_pts[seg_index,:])

        seg_types[seg_index] = seg_type
        plot_for_compacts[seg_index] = plot_for_compact

    if debug_flag == True:
        print('seg_types = ')
        print(seg_types)
        print('plot_for_compacts = ')
        print(plot_for_compacts)

    for seg_index in range(new_nrows):
        # Special case for white outline of 2D response surface
        #   requires extra call to plot entire line at once to
        #   avoid getting a dashed line.
        seg_type = seg_types[seg_index]

        if (plot_params.slants_2D_flag == True \
                and plot_params.outline_slant_flag == True \
                and seg_type == snni.plot_segment_type['SLANT']) \
            or (plot_params.straights_2D_flag == True \
                and plot_params.outline_straight_flag == True \
                and seg_type == snni.plot_segment_type['STRAIGHT']):

                respsurf_line_segment_plot( \
                    fig, ax, view1, plot_params, \
                    syn_shape, N, T, w_vec, X_vec, \
                    sorted_first_edge_pts[seg_index,:], \
                    sorted_second_edge_pts[seg_index,:], \
                    seg_types[seg_index], \
                    plot_for_compacts[seg_index], \
                    outline_flag = True)

        # Plot segment normally (i.e., not white outline).
        respsurf_line_segment_plot( \
                fig, ax, view1, plot_params, \
                syn_shape, N, T, w_vec, X_vec, \
                sorted_first_edge_pts[seg_index,:], \
                sorted_second_edge_pts[seg_index,:], \
                seg_types[seg_index], \
                plot_for_compacts[seg_index], \
                outline_flag = False)

    # No return value.  Just makes plot.
    return



"""
#######################################################################
resp_surf_plot( \
        fig, ax, view1, plot_params, syn_shape, N, T, w_vec, \
        debug_flag=False):
    """
"""
    resp_surf_plot( \
        fig, ax, view1, plot_params, syn_shape, N, T, w_vec, \
        debug_flag=False):
    return
    
    Plot parts of response surface for spiking neuron as specified by
    flags specifying what portions of response surface to plot.
    
    Hierarchies of function calls in outline form is as follows:
    resp_surf_plot()
        list_X_regions_to_plot()
            dec2tri()
        X_region_plot_volumes_collect()
            X_region_plot_volume_create()
        sort_plot_volumes_by_depth()
        resp_surf_facet_plot()
            rs_line_segment_category
            sort_X_region_plot_entities()
            resp_surf_Xregion_edge_intersect_pts()
            plot_rs_line_segment()
                syn_waveform()
                syn_inverse_waveform()
                syn_slope()
    
    Inputs:
        fig = ptr to figure
        ax = ptr to axes of figure
        syn_shape = (int, dictionary syn_wave_shape from
            syn_waveforms.py) syanpse response waveform shape
        neuron_A = (class SpikingNeuron from snn_neuron.py) neuron
            synaptic weights and threshold
        plot_flags = (class RS_WhatToPlot) what parts of response
            surface to plot, such as which X-cubes and embellishments
        view1 = (class ViewPt from View_3dim_in_2dim.two_dim_view3D) 
            viewpoint and focal point
        plot_params = (class RS_PlotParams)
    Outputs:
        no values
    
    Orig Authors: Fatemeh Koohestan Mahalian and Neil E Cotter
    Python Port: Neil E Cotter
    Date Created: 07/16/2021
    Python Version: 3.8.8
    Ported From: MATLAB SNN__3_D_Resp_Surf_Realistic_Syn_Plot5.m
    """
"""

    # Generate list of X-vecs in which plotting might be needed.
    # X-vecs that are not needed (as per plot flags) are dropped.
    X_vecs_to_use = list_X_regions_to_plot( \
            fig, ax, plot_params, debug_flag=False):

    # Create volumes in X-regions in which plotting may occur.  The
    #   volumes are specified by opposite corners.
#    X_vecs_list, lower_corner_pt_mat, upper_corner_pt_mat = \
#        X_region_plot_volumes_collect(syn_shape, plot_flags, \
#           all_X_vecs)
    X_vecs_list, X_plot_vols_low_corners, X_plot_vols_high_corners = \
            X_region_plot_volumes_create( \
                plot_params, syn_shape, X_vecs_to_use, \
                all_X_signs_vec, debug_flag=False):

    # Sort the plot volumes by distance from the observer's viewpoint
    #   so X-regions in back may be plotted first with closer regions
    #   layered on top of those further away from observer.
#    sorted_X_vec_by_dist_list, sorted_lower_corner_pt_mat, \
#        sorted_upper_corner_pt_mat = \
#            sort_plot_volumes_by_depth(view1, X_vecs_list, \
#                lower_corner_pt_mat, upper_corner_pt_mat)
    sorted_X_vecs_list, sorted_X_plot_vols_low_corners, \
            sorted_X_plot_vols_high_corners = \
                sort_plot_volumes_by_depth( \
                    view1, X_vecs_list, \
                    X_plot_vols_low_corners, X_plot_vols_high_corners)

    # Calculate X_edge_intersect_pts.
    for X_vec_index, this_X-vec in enumerate(sorted_X_vecs_list)
        # Find plot lines as intersections of response surface planes
        #   and slices through X-regions parallel to t_i axes.
        X_low_corner = sorted_X_plot_vols_low_corners[X_vec_index]
        X_high_corner = sorted_X_plot_vols_high_corners[X_vec_index]

        num_intersect_pts, X_edge_intersect_pts = \
                respsurf_Xregion_edge_intersect_pts( \
                    plot_params.n_slices, X_vec, X_low_corner, \
                    X_high_corner, N, T, w_vec)

        # Make plot of response surface in X-region.
        #   No values returned; just plots response surface.
        resp_surf_Xregion_plot(fig, ax, view1, plot_params, syn_shape, \
                X_vec, N, T, w_vec, X_edge_intersect_pts, \
                debug_flag=True)
"""


#######################################################################
def main():
    #if __name__ == "__main__":
    #print(__name__)
    # Set up parameters if file is run stand-alone.
    #syn_shape = syn_wave_shape['TRIANGULAR_SYMMETRIC']

    syn_shape = syn_wave_shape['SYN_TRIANGULAR_SYMMETRIC']
    #syn_shape = syn_wave_shape['SYN_LINEAR_EXTENDED']
    #syn_shape = syn_wave_shape['SYN_PARABOLIC']
    #syn_shape = syn_wave_shape['SYN_COSINE']
    #syn_shape = syn_wave_shape['SYN_ALPHA_FUNC']
    #syn_shape = syn_wave_shape['SYN_OVAL']

    # Set view point in 3D.  Nominally in approximately (1,1,1) dir.
    view1 = view2D.ViewPt()
    """
    Nominal settings:
    view1.view_point = np.array([2.8, 3.2, 5])
    view1.focal_point = np.array([0.0, 0.0, 0.0])
    view1.origin = np.array([0.0, 0.0, 0.0] - view1.focal_point)
    """
    # Other values for view point.
    # view_point = [2.8,3.2,5];   # default:  view_point = [3,4,5];
    # view_point = [-2.8,3.2,-5]  # default:  view_point = [3,4,5];
    # view_point = [-3, 3,-5]
    # focal_point = [0 0 0]       # default:  focal_point = [0 0 0];
    # axis_box = [-3, 3,-3, 3]    # default:  axis_box = [-3, 3,-3, 3];
    # syn_shape = 0
    # axis_box = [-3, 4,-4, 4]    # default:  axis_box = [-3, 4,-4, 4];
    # syn_shape = 4
    # axis_box = [-3, 3,-3, 4]    # default:  axis_box = [-3, 3,-3, 4];
    # syn_shape = 1,2,3,5

    fig, ax = setup_respsurf_plot()

    draw_X_cubes(fig, ax, view1, syn_shape, True, True)

    draw_respsurf_axes(fig, ax, view1, syn_shape, True, True, True)

    plot_params = snni.RS_PlotParams()
    """
    plot_params.n_slices = 21
    plot_params.self.n_slices_last_dim = 21
    plot_params.one_dim_circle_radius = 0.05   # In units of plot axes.
    
    Nominal plot flags:
    plot_params.facets_3D_flag = True
    plot_params.strips_3D_flag = True
    plot_params.walls_3D_flag = True
    plot_params.slants_2D_flag = False
    plot_params.straights_2D_flag = False
    plot_params.points_1D_flag = False
    plot_params.ignore_neg_slope = False
    plot_params.compact_plot_flag = True
    plot_params.outline_3D_flag = True
    plot_params.outline_slant_flag = True
    plot_params.outline_straight_flag = True
    plot_params.darken_inside_rs_colors_flag = True
    
    """
    plot_params.n_slices = 21
    plot_params.n_slices_last_dim = 11

    plot_params.facets_3D_flag = False
    plot_params.strips_3D_flag = False
    plot_params.walls_3D_flag = False
    plot_params.slants_2D_flag = False
    plot_params.straights_2D_flag = False
    plot_params.points_1D_flag = True
    plot_params.ignore_neg_slope = False
    plot_params.compact_plot_flag = False
    plot_params.outline_3D_flag = False
    plot_params.outline_slant_flag = False
    plot_params.outline_straight_flag = False
    plot_params.darken_inside_rs_colors_flag = False

    #-----------------------------------------------------------------#
    # Define neuron.  Single neuron here, otherwise we use arrays.
    N = 3       # 3 synapses fire at times t_1, t_2, and t_3
    T = 1.0     # Threshold
    w_vec = np.array([10/9, 8/9, 6/9])  # Synaptic wts that allow
                                        #   3D, 2D, and 1D solns.
    #delay = np.array([0.0, 0.0, 0.0])   # Synaptic input delays.
    """
    Values used in original paper:
    neuron_A.N = 3
    neuron_A.T = 1.125
    neuron_A.w = np.array([1.25, 1.00, 0.75])
    neuron_A.delay = np.array([0, 0, 0])
    """
    
    print("w_vec = ")
    print(w_vec)

    # Weight vecs used in the past:
    # Default:  w = [1.25, 1.00, 0.75]

    # neuron1.w = np.array([0.4,0.4, 0.4])
    
    # Testing 1-dim solutions
    # neuron1.w = np.array(1.25 * [1.0, 1.0, 1.0])

    # w_vec = [0.8, 0.8, 0.8]
    
    #X_vec = np.array([1,1,1], dtype=int)
    #X_vec = np.array([1,1,-1], dtype=int)
    #X_vec = np.array([1,-1,1], dtype=int)
    #X_vec = np.array([-1,1,1], dtype=int)
    #X_vecs = np.array([[1,1,0],[1,1,1]], dtype=int)
    #print('X_vecs = ')
    #print(X_vecs,'\n')

    #X_signs_vecs = np.array([[0,0,-1],[0,0,0]], dtype=int)

    debug_X_vec_flag = False

    X_vecs_list = \
            Xi.list_X_regions_to_plot(plot_params, N, \
                debug_flag=False)
    if debug_X_vec_flag == True:
        print('after Xc.list_X_regions_to_plot()')
        print(' X_vecs_list.shape = \n',X_vecs_list.shape)
        print(' X_vecs_list = \n',X_vecs_list)

    X_vecs_aug, X_signs_vecs_aug = \
            Xi.create_X_signs_vecs( \
                plot_params, syn_shape, X_vecs_list, debug_flag=False)
    if debug_X_vec_flag == True:
        print('after Xc.create_X_signs_vecs()')
        print(' X_vecs.shape = \n',X_vecs_aug.shape)
        print(' X_signs_vecs.shape = \n',X_signs_vecs_aug.shape)
        for index_X_signs_vec, X_signs_vec in \
                enumerate(X_signs_vecs_aug):
            print(' index_X_signs_vec = ',index_X_signs_vec)
            print(' X_vecs_aug[index_X_signs_vec] = \n', \
                    X_vecs_aug[index_X_signs_vec])
            print(' X_signs_vecs_aug[index_X_signs_vec] = \n', \
                    X_signs_vecs_aug[index_X_signs_vec],'\n')

    X_low_corners_aug, X_high_corners_aug = \
            Xi.X_region_plot_volumes_create( \
                    syn_shape, plot_params, X_vecs_aug, \
                    X_signs_vecs_aug)
    if debug_X_vec_flag == True:
        print('after Xc.X_region_plot_volumes_create()')
        print(' X_low_corners_aug.shape = \n',X_low_corners_aug.shape)
        print(' X_high_corners_aug.shape = \n',X_high_corners_aug.shape)
        print(' X_low_corners_aug = \n',X_low_corners_aug)
        print(' X_high_corners_aug = \n',X_high_corners_aug)

    # Sort X regions by distance of center from viewer.  Plot back 1st.
    X_vecs, X_signs_vecs, X_low_corners, X_high_corners = \
            Xi.sort_plot_volumes_by_depth( \
                view1, X_vecs_aug, X_signs_vecs_aug, \
                X_low_corners_aug, X_high_corners_aug, \
                debug_flag=False)
    if debug_X_vec_flag == True:
        print('after Xc.create_X_signs_vecs()')
        print(' X_vecs.shape = \n',X_vecs_aug.shape)
        print(' X_signs_vecs.shape = \n',X_signs_vecs_aug.shape)
        print(' X_low_corners.shape = \n',X_low_corners_aug.shape)
        print(' X_high_corners.shape = \n',X_high_corners_aug.shape)
        for index_X_vec, X_vec in \
                enumerate(X_vecs):
            print(' index_X_vec = ',index_X_vec)
            print(' X_vecs[index_X_vec] = \n', \
                    X_vecs[index_X_vec])
            print(' X_signs_vecs[index_X_vec] = \n', \
                    X_signs_vecs[index_X_vec],'\n')
            print(' X_low_corners[index_X_vec] = \n', \
                    X_low_corners[index_X_vec])
            print(' X_high_corners[index_X_vec] = \n', \
                    X_high_corners[index_X_vec],'\n')

    debug_flag = False

    for index_X_vec, X_vec in enumerate(X_vecs):
        print('Processing and plotting X_vec =   X_signs_vec =')
        print(X_vec,'                        ', \
                X_signs_vecs[index_X_vec])

        num_intersect_pts, X_edge_intersect_pts = \
                Xi.respsurf_Xregion_edge_intersect_pts( \
                    plot_params.n_slices, X_vec, \
                    X_low_corners[index_X_vec,:], \
                    X_high_corners[index_X_vec,:], N, T, w_vec, \
                    debug_flag=False)

        if debug_flag == True:
            print('num_intersect_pts = ')
            print(num_intersect_pts)
            print('X_edge_intersect_pts = ')
            print(X_edge_intersect_pts,'\n')

        resp_surf_Xregion_plot( \
                fig, ax, view1, plot_params, syn_shape, X_vec, N, T, \
                w_vec, X_edge_intersect_pts, debug_flag=False)


    plt.savefig('draw_cubes_and_axes.png')
    plt.savefig('draw_cubes_and_axes.eps', format='eps')

    return


#######################################################################
if __name__ == "__main__":
    main()

