'''
Created on 16-Apr-2021

@author: bthakur
'''
import os 
import numpy as np
import random
import inspect
import traceback

import matplotlib.pyplot as plt
from xv.km.ui import SvgHelper         

from sympy import (Symbol)


from ..helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate


# _quiver_manager
# QuiverManager
        
class QuiverManager(BaseManager):
    '''
    How to work with quivers
    Example:
        ke = QuiverManager()
        ke
        
        ke.printProblemTypes()
        
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printLength(2, 5, 3, -1)
        ke.printMovementLengths()        
        
        
    '''    
    def __new__(cls, *args, **kwargs):
        instance = super(QuiverManager, cls).__new__(cls, *args, **kwargs)
        for base_class in QuiverManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance
    
    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        pass


    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_cartesian_product_meshgrid',
            '_problem_quiver_and_stream_plotting',
            '_problem_quiver_and_stream_plotting_2',
            '_problem_quiver_and_stream_plotting_3',
            '_problem_field_of_one_charge',
            '_problem_field_of_two_charges',
            '_problem_popential_of_one_charge',
         ])
        pass

    def _problem_cartesian_product_meshgrid(self, *args, **kwargs):
        """
        Use meshgrid, ravel, newaxis, hstack to create a cartesian product of two list of values

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_cartesian_product_meshgrid')

        doc_style: xv_doc
        """

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        shape = np.random.randint(1, 9, size = 2)
        arr_x = np.random.randint(1, 9, size = (shape[0]) )
        arr_y = np.random.randint(1, 9, size = (shape[1]) )
        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)
        
        X_flattened = X_meshgrid.ravel()
        Y_flattened = Y_meshgrid.ravel()
        
        X_with_extra_dim = X_flattened[:, np.newaxis]
        Y_with_extra_dim = Y_flattened[:, np.newaxis]
        
        points = np.hstack([X_with_extra_dim, Y_with_extra_dim])
        
        
        plt.ioff()
        fig, ax = plt.subplots()
        
        for point in points:
            plt.plot(point[0], point[1], marker = 'o')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        problem_s = f"""
        Create points using all possible points from values
        x = {arr_x}
        y = {arr_y}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        x = {arr_x}
        y = {arr_y}

        <b>Create a meshgrid:</b>
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        arr_x has been repeated for every value of arr_y.
        In this case, it is repeated {arr_y.shape} times.
        X_meshgrid = 
        {X_meshgrid}
        
        Every element of arr_y has been repeated for the shape of arr_x. 
        In this case it is repeated {arr_x.shape} times.
        Y_meshgrid = 
        {Y_meshgrid}


        
        <b>Flatten the meshgrids:</b>
        X_flattened = X_meshgrid.ravel()
        Y_flattened = Y_meshgrid.ravel()
        
        X_flattened = 
        {X_flattened}

        Y_flattened = 
        {Y_flattened}

        <b>Add extra dimension to flattened arrays:</b>
        X_with_extra_dim = X_flattened[:, np.newaxis]
        Y_with_extra_dim = Y_flattened[:, np.newaxis]
        
        X_with_extra_dim = 
        {X_with_extra_dim}

        Y_with_extra_dim = 
        {Y_with_extra_dim}

        <b>Create all possible points:</b>
        points = np.hstack([X_with_extra_dim, Y_with_extra_dim])

        Note that the result has all possible combinations from arr_x and arr_y
        The shapes of original arrays were:
        arr_x = {arr_x.shape}
        arr_y = {arr_y.shape}
        The shape of result is {points.shape}.

        points = 
        {points}

        <b>Plot the points</b>
        import numpy as np
        import matplotlib.pyplot as plt

        arr_x = np.{repr(arr_x)}
        arr_y = np.{repr(arr_y)}

        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)
        
        X_flattened = X_meshgrid.ravel()
        Y_flattened = Y_meshgrid.ravel()
        
        X_with_extra_dim = X_flattened[:, np.newaxis]
        Y_with_extra_dim = Y_flattened[:, np.newaxis]
        
        points = np.hstack([X_with_extra_dim, Y_with_extra_dim])
        
        fig, ax = plt.subplots(figsize=(9,9))
        
        for point in points:
            &nbsp;&nbsp;&nbsp;&nbsp;ax.plot(point[0], point[1], marker = 'o')
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-10, 10, -10, 10])
        ax.set_aspect('equal')
        
        plt.show()
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        {points}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass
    
    def _problem_quiver_and_stream_plotting(self, *args, **kwargs):
        """
        Plot quiver and stream of a given field

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_quiver_and_stream_plotting')

        doc_style: xv_doc
        """

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        intervals = 20
        arr_x = np.linspace(-1, 1, intervals)
        arr_y = np.linspace(-1, 1, intervals)

        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        X_direction = np.sin(X_meshgrid) * np.cos(Y_meshgrid)
        Y_direction = -np.cos(X_meshgrid) * np.sin(Y_meshgrid)


        plt.ioff()
        fig, ax = plt.subplots(figsize=(9,9))
        
        
        ax.quiver(X_meshgrid, Y_meshgrid, X_direction, Y_direction)
        ax.streamplot(X_meshgrid, Y_meshgrid, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-1, 1, -1, 1])
        ax.set_aspect('equal')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        F = Symbol('F')
        i = Symbol('i')
        j = Symbol('j')
        x = Symbol('x')
        y = Symbol('y')
        
        problem_s = f"""
        Create quiver and stream plots for the following field:
    
        $\\vec {F} = \\frac {x}{5} \\hat {i} - \\frac {y}{5} \\hat {j}$
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Divide the range of values into {intervals} intervals:</b>
        intervals = 20
        arr_x = np.linspace(-1, 1, intervals)
        arr_y = np.linspace(-1, 1, intervals)
        
        <b>Create a meshgrid of x and y values:</b>
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        <b>create direction vectors:</b>
        The field is defined as 
        
        $\\vec {F} = \\frac {x}{5} \\hat {i} - \\frac {y}{5} \\hat {j}$
        
        # So, calculate field in $\\hat {i}$ and $\\hat {j}$ directions:
        
        X_direction = X_meshgrid / 5
        Y_direction = Y_meshgrid / 5

        <b>Plot:</b>
        import numpy as np
        import matplotlib.pyplot as plt
        
        intervals = 20
        arr_x = np.linspace(-1, 1, intervals)
        arr_y = np.linspace(-1, 1, intervals)

        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        X_direction = np.sin(X_meshgrid) * np.cos(Y_meshgrid)
        Y_direction = -np.cos(X_meshgrid) * np.sin(Y_meshgrid)

        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.quiver(X_meshgrid, Y_meshgrid, X_direction, Y_direction)
        ax.streamplot(X_meshgrid, Y_meshgrid, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-1, 1, -1, 1])
        ax.set_aspect('equal')
        
        plt.show()

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass
    
    def _problem_quiver_and_stream_plotting_2(self, *args, **kwargs):
        """
        Plot quiver and stream of a given field

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_quiver_and_stream_plotting_2')

        doc_style: xv_doc
        """

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        intervals = 20
        angles = np.linspace(0, 2 * np.pi, intervals)
        
        arr_x = angles
        arr_y = angles
        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        X_direction = np.sin(X_meshgrid) * np.cos(Y_meshgrid)
        Y_direction = -np.cos(X_meshgrid) * np.sin(Y_meshgrid)


        plt.ioff()
        fig, ax = plt.subplots(figsize=(9,9))
        
        
        ax.quiver(X_meshgrid, Y_meshgrid, X_direction, Y_direction)
        ax.streamplot(X_meshgrid, Y_meshgrid, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([0, 2 * np.pi, 0, 2 * np.pi])
        ax.set_aspect('equal')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        F = Symbol('F')
        i = Symbol('i')
        j = Symbol('j')
        
        problem_s = f"""
        Create quiver and stream plots for the following field:
        
        $\\vec {F} = sin(x)cos(y) \\hat {i} -cos(x)sin(y) \\hat {j}$
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Divide one cycle (2pi) into {intervals} intervals:</b>
        intervals = 20
        angles = np.linspace(0, 2 * np.pi, intervals)

        <b>Set x and y angles:</b>
        arr_x = angles
        arr_y = angles
        
        <b>Create a meshgrid of x and y values:</b>
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        <b>create direction vectors:</b>
        The field is defined as 
        
        $\\vec {F} = sin(x)cos(y) \\hat {i} -cos(x)sin(y) \\hat {j}$
        
        # So, calculate field in $\\hat {i}$ and $\\hat {j}$ directions:
        
        X_direction = np.sin(X_meshgrid) * np.cos(Y_meshgrid)
        Y_direction = -np.cos(X_meshgrid) * np.sin(Y_meshgrid)

        <b>Plot:</b>
        import numpy as np
        import matplotlib.pyplot as plt
        
        intervals = 20
        angles = np.linspace(0, 2 * np.pi, intervals)
        
        arr_x = angles
        arr_y = angles
        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        X_direction = np.sin(X_meshgrid) * np.cos(Y_meshgrid)
        Y_direction = -np.cos(X_meshgrid) * np.sin(Y_meshgrid)
        
        fig, ax = plt.subplots(figsize=(9,9))

        ax.quiver(X_meshgrid, Y_meshgrid, X_direction, Y_direction)
        ax.streamplot(X_meshgrid, Y_meshgrid, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([0, 2 * np.pi, 0, 2 * np.pi])
        ax.set_aspect('equal')
        
        plt.show()
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass
    
    def _problem_quiver_and_stream_plotting_3(self, *args, **kwargs):
        """
        Plot quiver and stream of a given gradient

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_quiver_and_stream_plotting_3')

        doc_style: xv_doc
        """


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        intervals = 20
        arr_x = np.linspace(-2, 2, intervals)
        arr_y = np.linspace(-2, 2, intervals)

        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        z = X_meshgrid * np.exp(-X_meshgrid ** 2 - Y_meshgrid ** 2)
        X_direction, Y_direction = np.gradient(z)


        plt.ioff()
        fig, ax = plt.subplots(figsize=(9,9))
        
        
        ax.quiver(X_meshgrid, Y_meshgrid, X_direction, Y_direction)
        ax.streamplot(X_meshgrid, Y_meshgrid, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-1, 1, -1, 1])
        ax.set_aspect('equal')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        F = Symbol('F')
        i = Symbol('i')
        j = Symbol('j')
        x = Symbol('x')
        y = Symbol('y')
        z = Symbol('z')
        
        problem_s = f"""
        Create quiver and stream plots for the following gradient:
    
        ${z} = {x} e^{{ -{x}^2 - {y}^2 }} $
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Divide the range of values into {intervals} intervals:</b>
        intervals = 20
        arr_x = np.linspace(-2, 2, intervals)
        arr_y = np.linspace(-2, 2, intervals)

        

        
        <b>Create a meshgrid of x and y values:</b>
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        <b>create direction vectors:</b>
        The gradient function is defined as 
        
        ${z} = {x} e^{{ -{x}^2 - {y}^2 }} $
        
        z = X_meshgrid * np.exp(-X_meshgrid ** 2 - Y_meshgrid ** 2)
        X_direction, Y_direction = np.gradient(z)

        <b>Plot:</b>
        import numpy as np
        import matplotlib.pyplot as plt
        
        intervals = 20
        arr_x = np.linspace(-2, 2, intervals)
        arr_y = np.linspace(-2, 2, intervals)
        
        X_meshgrid, Y_meshgrid = np.meshgrid(arr_x, arr_y)

        z = X_meshgrid * np.exp(-X_meshgrid ** 2 - Y_meshgrid ** 2)
        X_direction, Y_direction = np.gradient(z)
        
        fig, ax = plt.subplots(figsize=(9,9))
        ax.quiver(X_meshgrid, Y_meshgrid, X_direction, Y_direction)
        ax.streamplot(X_meshgrid, Y_meshgrid, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-2, 2, -2, 2])
        ax.set_aspect('equal')
        
        plt.show()
        """
        
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass


    
    def _problem_field_of_one_charge(self, *args, **kwargs):
        """
        Plot quiver and stream of field one charge

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_field_of_one_charge')

        doc_style: xv_doc
        """

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        intervals = 40
        p1 = np.array([-1, 0])
        
        arr_x = np.linspace(-4, 4, intervals)
        arr_y = np.linspace(-4, 4, intervals)
        
        X, Y = np.meshgrid(arr_x, arr_y)

        X_direction = (X - p1[0])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  )
        
        
        Y_direction = (Y - p1[1])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) 
        
        

        plt.ioff()
        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.plot(*p1,'-or')
        
        ax.quiver(X, Y, X_direction, Y_direction)
        ax.streamplot(X, Y, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-4, 4, -4, 4])
        ax.set_aspect('equal')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        F = Symbol('F')
        i = Symbol('i')
        j = Symbol('j')
        x = Symbol('x')
        y = Symbol('y')
        
        problem_s = f"""
        Plot quiver and stream of one charge
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Divide the range of values into {intervals} intervals:</b>

        intervals = 40
        arr_x = np.linspace(-4, 4, intervals)
        arr_y = np.linspace(-4, 4, intervals)

        X, Y = np.meshgrid(arr_x, arr_y)


        <b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        
        
        <b>Calculate field values:</b>

        X_direction = (X - p1[0])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) 
        
        
        Y_direction = (Y - p1[1])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) 
        

        <b>Plot:</b>
        import numpy as np
        import matplotlib.pyplot as plt
        
        #<b>Divide the range of values into {intervals} intervals:</b>

        intervals = 40
        arr_x = np.linspace(-4, 4, intervals)
        arr_y = np.linspace(-4, 4, intervals)

        X, Y = np.meshgrid(arr_x, arr_y)


        #<b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        
        
        #<b>Calculate field values:</b>

        X_direction = (X - p1[0])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) 
        
        
        Y_direction = (Y - p1[1])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) 
        

        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.plot(*p1,'-or')
        
        ax.quiver(X, Y, X_direction, Y_direction)
        ax.streamplot(X, Y, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-4, 4, -4, 4])
        ax.set_aspect('equal')
        
        plt.show()

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass


    def _problem_field_of_two_charges(self, *args, **kwargs):
        """
        Plot quiver and stream of field of two charges

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_field_of_two_charges')

        doc_style: xv_doc
        """

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        intervals = 40
        p1 = np.array([-1, 0])
        p2 = np.array([1, 0])
        
        arr_x = np.linspace(-4, 4, intervals)
        arr_y = np.linspace(-4, 4, intervals)
        
        X, Y = np.meshgrid(arr_x, arr_y)

        #X_direction = (X + 1)/((X+1) ** 2 + Y ** 2) - (X - 1)/((X-1) ** 2 + Y ** 2)
        #Y_direction = Y/((X+1) ** 2 + Y ** 2) - Y/((X-1) ** 2 + Y ** 2)
        
        X_direction = (X - p1[0])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) - (X - p2[0])/(
                                (X - p2[0]) ** 2 + (Y - p2[1]) ** 2
                  )
        
        
        Y_direction = (Y - p1[1])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) - (Y - p2[1])/(
                                (X - p2[0]) ** 2 + (Y - p2[1]) ** 2
                  )
        
        

        plt.ioff()
        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.plot(*p1,'-or')
        ax.plot(*p2,'-ob')
        
        ax.quiver(X, Y, X_direction, Y_direction)
        ax.streamplot(X, Y, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-4, 4, -4, 4])
        ax.set_aspect('equal')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        F = Symbol('F')
        i = Symbol('i')
        j = Symbol('j')
        x = Symbol('x')
        y = Symbol('y')
        
        problem_s = f"""
        Plot quiver and stream of two charges
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Divide the range of values into {intervals} intervals:</b>

        intervals = 40
        arr_x = np.linspace(-4, 4, intervals)
        arr_y = np.linspace(-4, 4, intervals)

        X, Y = np.meshgrid(arr_x, arr_y)


        <b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        p2 = np.array([1, 0])
        
        
        <b>Calculate field values:</b>

        X_direction = (X - p1[0])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) - (X - p2[0])/(
                                (X - p2[0]) ** 2 + (Y - p2[1]) ** 2
                  )
        
        
        Y_direction = (Y - p1[1])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) - (Y - p2[1])/(
                                (X - p2[0]) ** 2 + (Y - p2[1]) ** 2
                  )
        

        <b>Plot:</b>
        import numpy as np
        import matplotlib.pyplot as plt
        
        #<b>Divide the range of values into {intervals} intervals:</b>

        intervals = 40
        arr_x = np.linspace(-4, 4, intervals)
        arr_y = np.linspace(-4, 4, intervals)

        X, Y = np.meshgrid(arr_x, arr_y)


        #<b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        p2 = np.array([1, 0])
        
        
        #<b>Calculate field values:</b>

        X_direction = (X - p1[0])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) - (X - p2[0])/(
                                (X - p2[0]) ** 2 + (Y - p2[1]) ** 2
                  )
        
        
        Y_direction = (Y - p1[1])/(
                                (X - p1[0]) ** 2 + (Y - p1[1]) ** 2
                  ) - (Y - p2[1])/(
                                (X - p2[0]) ** 2 + (Y - p2[1]) ** 2
                  )
        

        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.plot(*p1,'-or')
        ax.plot(*p2,'-ob')
        
        ax.quiver(X, Y, X_direction, Y_direction)
        ax.streamplot(X, Y, X_direction, Y_direction, density = 1)
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-4, 4, -4, 4])
        ax.set_aspect('equal')
        
        plt.show()

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass

    def _problem_popential_of_one_charge(self, *args, **kwargs):
        """
        Plot potential of one charge

        Minimum Grade: 6
        Maximum Grade: 12
    
        Examples
        --------
        from xv.math.geometry import QuiverManager
        ke = QuiverManager()

        ke.getRandomProblem(problem_type = '_problem_popential_of_one_charge')

        doc_style: xv_doc
        """

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        intervals = 40
        p1 = np.array([-1, 0])
        
        arr_x = np.linspace(-1, 1, intervals)
        arr_y = np.linspace(-1, 1, intervals)
        
        X, Y = np.meshgrid(arr_x, arr_y)

        potential = 1 / (np.sqrt((X - p1[0])**2 + (Y - p1[1])**2))


        plt.ioff()
        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.plot(*p1,'-or')

        ax.pcolormesh(X, Y, potential, 
                            vmin = -1, 
                              vmax = 1,
                              shading='auto')
        
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-1, 1, -1, 1])
        ax.set_aspect('equal')
        
        svgHelper = SvgHelper()
        svg_str = svgHelper.plt_to_svg()
        plt.clf()
        plt.close()
        
        F = Symbol('F')
        i = Symbol('i')
        j = Symbol('j')
        x = Symbol('x')
        y = Symbol('y')
        
        problem_s = f"""
        Plot potential of one charge
        
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Divide the range of values into {intervals} intervals:</b>

        intervals = 40
        
        arr_x = np.linspace(-1, 1, intervals)
        arr_y = np.linspace(-1, 1, intervals)
        
        X, Y = np.meshgrid(arr_x, arr_y)


        <b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        
        
        <b>Calculate potential values:</b>

        potential = 1 / (np.sqrt((X - p1[0])**2 + (Y - p1[1])**2))
        

        <b>Plot:</b>
        import numpy as np
        import matplotlib.pyplot as plt
        
        #<b>Divide the range of values into {intervals} intervals:</b>

        intervals = 40
        
        arr_x = np.linspace(-1, 1, intervals)
        arr_y = np.linspace(-1, 1, intervals)
        
        X, Y = np.meshgrid(arr_x, arr_y)


        #<b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        
        
        #<b>Define location of charges:</b>
        p1 = np.array([-1, 0])
        
        
        #<b>Calculate potential values:</b>

        potential = 1 / (np.sqrt((X - p1[0])**2 + (Y - p1[1])**2))
        

        fig, ax = plt.subplots(figsize=(9,9))
        
        ax.plot(*p1,'-or')

        ax.pcolormesh(X, Y, potential, 
                            vmin = -1, 
                              vmax = 1,
                              shading='auto')
        
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
        ax.axis([-1, 1, -1, 1])
        ax.set_aspect('equal')
        
        plt.show()

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        problemTemplate.add_solution(svg_str, 'text/svg')
        
        problemTemplate.add_answer(svg_str, 'text/svg')
 
        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
        pass
