def xmkpy3_finder_chart_tpf_overlay_v6():
    import matplotlib.pyplot as plt
    import astropy.units as u
    import sys
    import os
    import ntpath
    import argparse
    import ast

    import lightkurve as lk  # ignore PEP8 warning of redefinition
    lk.log.setLevel('INFO')

    import mkpy3

    #
    # argparse: BEGIN =========================================================
    #
    parser = argparse.ArgumentParser()
    #
    parser.add_argument(
        '--tpf_filename',
        action="store",
        type=str,
        default=None,
        help="Filename of the Target Pixel File (TPF) [default: None]")
    parser.add_argument('--frame',
                        action="store",
                        type=int,
                        default=0,
                        help='Frame number (integer) [default: 0]')
    parser.add_argument('--survey',
                        action="store",
                        type=str,
                        default='2MASS-J',
                        help="Survey name (str) [default: '2MASS-J']")
    parser.add_argument(
        '--width_height_arcmin',
        action="store",
        type=float,
        default=2.0,
        help='Width and height size in arcmin (float) [default: 2.0]')
    parser.add_argument('--show_plot',
                        type=mkpy3.mkpy3_util_str2bool,
                        default=True,
                        help='If True, show the plot [default=True]')
    parser.add_argument(
        '--plotfile',
        action="store",
        type=str,
        default='mkpy3_plot.png',
        help="Filename of the output plotfile [default: 'mkpy3_plot.png']")
    parser.add_argument(
        '--overwrite',
        type=mkpy3.mkpy3_util_str2bool,
        default=False,
        help='If True, overwrite ("clobber") an existing output file '
        '[default: False.')
    parser.add_argument(
        '--figsize',
        action="store",
        type=ast.literal_eval,
        default="[9,9]",
        help="2-item list of figure width and height [Matplotlib] (str) "
        "[default: \"[9,9]\"")
    parser.add_argument('--title',
                        action="store",
                        type=str,
                        default=None,
                        help='Title of the finder chart (str) [default: None]')
    parser.add_argument(
        '--percentile',
        action="store",
        type=float,
        default=99.0,
        help='Percentile [percentage of pixels to keep: 0.0 to 100.0] '
        '(float) [default: 99.0]')
    parser.add_argument(
        '--cmap',
        action="store",
        type=str,
        default=None,
        help="Colormap name [Matplotlib] (str) [default: 'gray']")
    parser.add_argument(
        '--colors',
        action="store",
        type=ast.literal_eval,
        default="[None,'cornflowerblue','red']",
        help="3-item list of overlay color names [Matplotlib] (str) "
        "[default: \"['None','cornflowerblue','red']\"")
    parser.add_argument(
        '--lws',
        action="store",
        type=ast.literal_eval,
        default="[0,3,4]",
        help="3-item list of overlay line widths [Matplotlib] (str) "
        "[default: \"[0,3,4]\"")
    parser.add_argument(
        '--zorders',
        action="store",
        type=ast.literal_eval,
        default="[0,1,2]",
        help="3-item list of overlay zorder values [Matplotlib] (str) "
        "[default: \"[0,1,2]\"")
    parser.add_argument(
        '--marker_dict',
        action="store",
        type=ast.literal_eval,
        default="{'edgecolor':'yellow', 's':600, 'facecolor':'None', 'lw':3, "
        "'zorder':10}",
        help="marker kwargs (dictonary string) for ax.scatter() [Matplotlib] "
        "(str) [default: \"{'edgecolor':'yellow', 's':600, 'facecolor':'None',"
        " 'lw':3, 'zorder':10}\"")
    parser.add_argument(
        '--verbose',
        type=mkpy3.mkpy3_util_str2bool,
        default=False,
        help='Print extra information if True (bool) [default=False]')
    #
    args = parser.parse_args()

    tpf_filename = args.tpf_filename
    frame = args.frame
    survey = args.survey
    width_height_arcmin = args.width_height_arcmin
    show_plot = args.show_plot
    plotfile = args.plotfile
    overwrite = args.overwrite
    figsize = args.figsize
    title_ = args.title
    percentile = args.percentile
    cmap = args.cmap
    colors = args.colors
    lws = args.lws
    zorders = args.zorders
    marker_dict = args.marker_dict
    verbose = args.verbose
    #
    if (verbose):
        print('%s =args.tpf_filename' % (args.tpf_filename))
        print('%s =args.frame' % (args.frame))
        print("'%s' =args.survey" % (args.survey))
        print('%s =args.width_height_arcmin' % (args.width_height_arcmin))
        print('%s =args.show_plot' % (args.show_plot))
        print("'%s' =args.plotfile" % (args.plotfile))
        print('%s =args.overwrite' % (args.overwrite))
        print('%s =args.figsize' % (args.figsize))
        print('%s =args.title' % (args.title))
        print('%s =args.percentile' % (args.percentile))
        print('%s =args.cmap' % (args.cmap))
        print('%s =args.colors' % (args.colors))
        print('%s =args.lws' % (args.lws))
        print('%s =args.zorders' % (args.zorders))
        print('%s =args.marker_dict' % (args.marker_dict))
        print('%s =args.verbose' % (args.verbose))
        print()
    # pass:if
    #
    # argparse: END ===========================================================
    #

    ok = (type(marker_dict) is dict) or (marker_dict is None)
    if (not ok):
        print()
        print('**** ERROR ***** BAD ARGUMENT VALUE *****')
        print()
        print('marker_dict must be a dictionary or None:')
        print(marker_dict, '=marker_dict')
        print()
        sys.exit(1)
    # pass:if

    if (tpf_filename is not None):
        mkpy3.mkpy3_util_check_file_exists(tpf_filename, True)
        tpf = lk.read(tpf_filename)
    else:
        tpf = lk.search_targetpixelfile(target='kepler-138b',
                                        mission='kepler',
                                        cadence='long',
                                        quarter=10).download(quality_bitmask=0)
        #   6--- exoplanet Kelper-138b is "KIC 7603200"
        print()
        print('No TargetPixelFile (TPF) filename given.')
        print()
        print('Using default TPF [Kepler Q10 observations of exoplanet Kepler-'
              '138b (KIC 760320)]:')
    # pass#if
    print()
    print('TPF filename:', ntpath.basename(tpf.path))
    print('TPF dirname: ', os.path.dirname(tpf.path))
    print()

    ra_deg = tpf.ra
    dec_deg = tpf.dec
    if (verbose):
        print()
        print(ra_deg, '=ra_deg')
        print(dec_deg, '=dec_deg')
    # pass#if

    print()

    # get survey image data
    # survey = '2MASS-J'  # hard-wired option
    survey_hdu, survey_hdr, survey_data, survey_wcs, survey_cframe = \
        mkpy3.mkpy3_finder_chart_survey_fits_image_get_v1(
            ra_deg, dec_deg, radius_arcmin=width_height_arcmin,
            survey=survey, verbose=verbose)

    # create a matplotlib figure object
    fig = plt.figure(figsize=figsize)

    # create a matplotlib axis object with right ascension and declination axes
    ax = plt.subplot(projection=survey_wcs)

    # show the survey image
    mkpy3.mkpy3_finder_chart_image_show_v1(ax=ax,
                                           image_data=survey_data,
                                           percentile=percentile,
                                           cmap=cmap,
                                           verbose=verbose)

    # show the TPF overlay
    mkpy3_finder_chart_tpf_overlay_v6(ax=ax,
                                      survey_wcs=survey_wcs,
                                      tpf=tpf,
                                      frame=frame,
                                      colors=colors,
                                      lws=lws,
                                      zorders=zorders,
                                      verbose=verbose)

    # add title
    if (title_ is None):
        title_ = tpf.hdu[0].header['object']
    # pass:if
    plt.suptitle(title_, size=25)

    # put a yellow circle at the target position
    if (type(marker_dict) is dict):
        ax.scatter(ra_deg * u.deg,
                   dec_deg * u.deg,
                   transform=ax.get_transform(survey_cframe),
                   **marker_dict)

    # adjust the plot margins
    plt.subplots_adjust(left=0.2, right=0.9, top=0.9, bottom=0.2)

    if (plotfile != ''):
        if (plotfile != 'mkpy3_plot.png'):
            mkpy3.mkpy3_util_check_file_exists(plotfile, overwrite)
        plt.savefig(plotfile, dpi=300)  # , bbox_inches = "tight")
        print('\n%s <--- plotfile written  :-)\n' % (plotfile))
    # pass:if

    if (show_plot):
        plt.ioff()
        plt.show()
    # pass:if

    plt.close()
示例#2
0
def xmkpy3_k2_tpf_overlay_v2():
    '''
Unit test
    '''
    import os
    import sys
    import ntpath
    import argparse
    import ast
    import lightkurve as lk
    #
    import mkpy3
    #
    # ===== argparse:BEGIN ====================================================
    #
    parser = argparse.ArgumentParser()
    #
    parser.add_argument(
        '--tpf_filename', action="store", type=str, default=None,
        help="Filename of the Target Pixel File (TPF) [default: None]")
    parser.add_argument(
        '--frame', action="store", type=int, default=0,
        help='Frame number (integer) [default: 0]')
    parser.add_argument(
        '--survey', action="store", type=str, default='2MASS-J',
        help="Survey name (str) [default: '2MASS-J']")
    parser.add_argument(
        '--width_height_arcmin', action="store", type=float, default=2.0,
        help='Width and height size in arcmin (float) [default: 2.0]')
    parser.add_argument(
        '--shrink', type=float, default=1.0,
        help='Survey search radius shrink factor (float) [default: 1.0]')
    parser.add_argument(
        '--show_plot', type=mkpy3.mkpy3_util_str2bool, default=True,
        help='If True, show the plot [default=True]')
    parser.add_argument(
        '--plot_file', action="store", type=str, default='mkpy3_plot.png',
        help='Filename of the output plot [default: "mkpy3_plot.png"]')
    parser.add_argument(
        '--overwrite', type=mkpy3.mkpy3_util_str2bool, default=False,
        help='If True, overwrite ("clobber") an existing output file '
        '[default: False]')
    parser.add_argument(
        '--figsize_str', action="store",
        type=ast.literal_eval, default="[9,9]",
        help="string of a 2-item list of figure width and height [Matplotlib] "
        "(str) [default: '[9,9]'")
    parser.add_argument(
        '--title', action="store", type=str, default=None,
        help='Title of the finder chart (str) [default: None]')
    parser.add_argument(
        '--percentile', action="store", type=float, default=99.0,
        help='Percentile [percentage of pixels to keep: 0.0 to 100.0] '
        '(float) [default: 99.0]')
    parser.add_argument(
        '--cmap', action="store", type=str, default=None,
        help="Colormap name [Matplotlib] (str) [default: 'gray_r']")
    parser.add_argument(
        '--colors_str', action="store",
        type=ast.literal_eval, default="[None,'cornflowerblue','red']",
        help="string of a 3-item list of overlay color names [Matplotlib] "
        "(str) [default: \"['None','cornflowerblue','red']\"")
    parser.add_argument(
        '--lws_str', action="store",
        type=ast.literal_eval, default="[0,3,4]",
        help="string of a 3-item list of overlay line widths [Matplotlib] "
        "(str) [default: \"[0,3,4]\"")
    parser.add_argument(
        '--zorders_str', action="store",
        type=ast.literal_eval, default="[0,2,4]",
        help="string of a 3-item list of overlay zorder values [Matplotlib] "
        "(str) [default: \"[0,2,4]\"")
    kwargs_ = "{'edgecolor':'yellow', 's':600, 'facecolor':'None', 'lw':3, "\
        "'zorder':10}"
    parser.add_argument(
        '--marker_kwargs_str', action="store",
        type=ast.literal_eval, default=kwargs_,
        help="marker kwargs (string of a dictonary) for ax.scatter() "
        "[Matplotlib] " + '(str) [default: "' + kwargs_ + '"')
    kwargs_ = "{'edgecolor':'cyan', 's':300, 'facecolor':'None', 'lw':3, "\
        "'zorder':20}"
    parser.add_argument(
        '--gaia_dr2_kwargs_str', action="store",
        type=ast.literal_eval, default=kwargs_,
        help="GAIA DR2 marker kwargs (string of a dictonary) for ax.scatter() "
        "[Matplotlib] "'(str) [default: "' + kwargs_ + '"')
    kwargs_ = "{'s':900, 'color':'lawngreen', 'marker':'x', 'lw':5, "\
        "'zorder':30}"
    parser.add_argument(
        '--vsx_kwargs_str', action="store",
        type=ast.literal_eval, default=kwargs_,
        help="VSX marker kwargs (string of a dictonary) for ax.scatter() "
        "[Matplotlib] (str) [default: '" + kwargs_ + "'")
    parser.add_argument(
        '--sexagesimal', type=mkpy3.mkpy3_util_str2bool, default=False,
        help='Print catalog positions as sexagesimal [hms dms] if True (bool) '
        '[default=False]')
    parser.add_argument(
        '--verbose', type=mkpy3.mkpy3_util_str2bool, default=False,
        help='Print extra information if True (bool) [default=False]')
    #
    args = parser.parse_args()
    #
    # ===== argparse:END ======================================================
    #

    tpf_filename = args.tpf_filename
    frame = args.frame
    survey = args.survey
    width_height_arcmin = args.width_height_arcmin
    shrink = args.shrink
    show_plot = args.show_plot
    plot_file = args.plot_file
    overwrite = args.overwrite
    figsize_str = str(args.figsize_str)
    title = args.title
    percentile = args.percentile
    cmap = args.cmap
    colors_str = str(args.colors_str)
    lws_str = str(args.lws_str)
    zorders_str = str(args.zorders_str)
    marker_kwargs_str = str(args.marker_kwargs_str)
    gaia_dr2_kwargs_str = str(args.gaia_dr2_kwargs_str)
    vsx_kwargs_str = str(args.vsx_kwargs_str)
    sexagesimal = args.sexagesimal
    verbose = args.verbose

    print()
    if (tpf_filename is not None):
        mkpy3.mkpy3_util_check_file_exists(tpf_filename, True)
        tpf = lk.open(tpf_filename)
    else:
        print('No TargetPixelFile (TPF) filename given.\n')
        tpf = lk.search_targetpixelfile(
            target='k2-34b', mission='k2',
            campaign=18).download(quality_bitmask=0)
        # ^--- exoplanet K2-34b is "EPIC 21211088"
        print()
        print(
            'Using default TPF [K2 C18 observations of exoplanet K2-34b '
            '(EPIC 21211088)].')
        print()
        shrink *= 0.8
    # pass:if
    try:
        print('TPF filename:', ntpath.basename(tpf.path))
        print('TPF dirname: ', os.path.dirname(tpf.path))
        assert(tpf.mission == 'K2')
        print()
    except Exception:
        print(tpf_filename, '=tpf_filename')
        print('^--- *** ERROR *** This file does not appear to be a K2 '
              'TargetPixelFile')
        print()
        print('Bye...\n', flush=True)
        sys.exit(1)
    # pass:try

    ax = mkpy3.mkpy3_tpf_overlay_v6(
      tpf=tpf,
      frame=frame,
      survey=survey,
      width_height_arcmin=width_height_arcmin,
      shrink=shrink,
      show_plot=show_plot,
      plot_file=plot_file,
      overwrite=overwrite,
      figsize_str=figsize_str,
      title=title,
      percentile=percentile,
      cmap=args.cmap,
      colors_str=colors_str,
      lws_str=lws_str,
      zorders_str=zorders_str,
      marker_kwargs_str=marker_kwargs_str,
      gaia_dr2_kwargs_str=gaia_dr2_kwargs_str,
      vsx_kwargs_str=vsx_kwargs_str,
      sexagesimal=sexagesimal,
      verbose=verbose
    )
示例#3
0
def xmkpy3_tess_tpf_overlay_v6():
    """
Unit test
    """
    import argparse
    import ast
    import lightkurve as lk
    import mkpy3
    #
    #
    # ===== argparse:BEGIN ====================================================
    #
    parser = argparse.ArgumentParser()
    #
    parser.add_argument(
        '--tpf_filename', action="store", type=str, default=None,
        help="Filename of the Target Pixel File (TPF) [default: None]")
    parser.add_argument(
        '--frame', action="store", type=int, default=0,
        help='Frame number (integer) [default: 0]')
    parser.add_argument(
        '--survey', action="store", type=str, default='2MASS-J',
        help="Survey name (str) [default: '2MASS-J']")
    parser.add_argument(
        '--rotationAngle_deg', action="store",
        type=ast.literal_eval, default=None,
        help="Rotation angle in degrees (string) [default: None] "
        "[examples: None or 12.345 (float) or 'tpf'")
    parser.add_argument(
        '--width_height_arcmin', action="store", type=float, default=6.0,
        help='Width and height size in arcmin (float) [default: 6.0]')
    parser.add_argument(
        '--shrink', type=float, default=1.0,
        help='Survey search radius shrink factor (float) [default: 1.0]')
    parser.add_argument(
        '--show_plot', type=mkpy3.mkpy3_util_str2bool, default=True,
        help='If True, show the plot [default=True]')
    parser.add_argument(
        '--plot_file', action="store", type=str, default='mkpy3_plot.png',
        help='Filename of the output plot [default: "mkpy3_plot.png"]')
    parser.add_argument(
        '--overwrite', type=mkpy3.mkpy3_util_str2bool, default=False,
        help='If True, overwrite ("clobber") an existing output file '
        '[default: False]')
    parser.add_argument(
        '--figsize_str', action="store",
        type=ast.literal_eval, default="[9,9]",
        help="string of a 2-item list of figure width and height [Matplotlib] "
        "(str) [default: '[9,9]'")
    parser.add_argument(
        '--title', action="store", type=str, default=None,
        help='Title of the finder chart (str) [default: None]')
    parser.add_argument(
        '--percentile', action="store", type=float, default=99.5,
        help='Percentile [percentage of pixels to keep: 0.0 to 100.0] '
        '(float) [default: 99.5]')
    parser.add_argument(
        '--cmap', action="store", type=str, default=None,
        help="Colormap name [Matplotlib] (str) [default: 'gray_r']")
    parser.add_argument(
        '--colors_str', action="store",
        type=ast.literal_eval, default="[None,'dodgerblue','red']",
        help="string of a 3-item list of overlay color names [Matplotlib] "
        "(str) [default: \"['None','dodgerblue','red']\"")
    parser.add_argument(
        '--lws_str', action="store",
        type=ast.literal_eval, default="[0,3,4]",
        help="string of a 3-item list of overlay line widths [Matplotlib] "
        "(str) [default: \"[0,3,4]\"")
    parser.add_argument(
        '--zorders_str', action="store",
        type=ast.literal_eval, default="[0,2,4]",
        help="string of a 3-item list of overlay zorder values [Matplotlib] "
        "(str) [default: \"[0,2,4]\"")
    kwargs_ = "{'edgecolor':'yellow', 's':600, 'facecolor':'None', 'lw':3, "\
        "'zorder':10}"
    parser.add_argument(
        '--marker_kwargs_str', action="store",
        type=ast.literal_eval, default=kwargs_,
        help="marker kwargs (string of a dictonary) for ax.scatter() "
        "[Matplotlib] " + '(str) [default: "' + kwargs_ + '"')
    kwargs_ = "{'edgecolor':'cyan', 's':150, 'facecolor':'None', 'lw':3, "\
        "'zorder':20}"
    parser.add_argument(
        '--print_gaia_dr2', type=mkpy3.mkpy3_util_str2bool, default=True,
        help='If True, print the GAIA DR2 catalog results [default=True]')
    parser.add_argument(
        '--gaia_dr2_kwargs_str', action="store",
        type=ast.literal_eval, default=kwargs_,
        help="GAIA DR2 marker kwargs (string of a dictonary) for ax.scatter() "
        "[Matplotlib] "'(str) [default: "' + kwargs_ + '"')
    kwargs_ = "{'s':900, 'color':'lawngreen', 'marker':'x', 'lw':5, "\
        "'zorder':30}"
    parser.add_argument(
        '--print_vsx', type=mkpy3.mkpy3_util_str2bool, default=True,
        help='If True, print the VSX catalog results [default=True]')
    parser.add_argument(
        '--vsx_kwargs_str', action="store",
        type=ast.literal_eval, default=kwargs_,
        help="VSX marker kwargs (string of a dictonary) for ax.scatter() "
        "[Matplotlib] (str) [default: '" + kwargs_ + "'")
    parser.add_argument(
        '--sexagesimal', type=mkpy3.mkpy3_util_str2bool, default=False,
        help='Print catalog positions as sexagesimal [hms dms] if True (bool) '
        '[default=False]')
    parser.add_argument(
        '--verbose', type=mkpy3.mkpy3_util_str2bool, default=False,
        help='Print extra information if True (bool) [default=False]')
    #
    args = parser.parse_args()
    #
    # ===== argparse:END ======================================================
    #

    tpf_filename = args.tpf_filename
    frame = args.frame
    survey = args.survey
    rotationAngle_deg = args.rotationAngle_deg
    width_height_arcmin = args.width_height_arcmin
    shrink = args.shrink
    show_plot = args.show_plot
    plot_file = args.plot_file
    overwrite = args.overwrite
    figsize_str = str(args.figsize_str)
    title = args.title
    percentile = args.percentile
    cmap = args.cmap
    colors_str = str(args.colors_str)
    lws_str = str(args.lws_str)
    zorders_str = str(args.zorders_str)
    marker_kwargs_str = str(args.marker_kwargs_str)
    print_gaia_dr2 = args.print_gaia_dr2
    gaia_dr2_kwargs_str = str(args.gaia_dr2_kwargs_str)
    print_vsx = args.print_vsx
    vsx_kwargs_str = str(args.vsx_kwargs_str)
    sexagesimal = args.sexagesimal
    verbose = args.verbose

    if (tpf_filename is not None):
        mkpy3.mkpy3_util_check_file_exists(tpf_filename, True)
        tpf = lk.open(tpf_filename, quality_bitmask=0)
    # pass:if

    if (tpf_filename is None):
        tpf = None
    # pass:if

    shrink = 0.4
    ax = mkpy3_tess_tpf_overlay_v6(
      tpf=tpf,
      frame=frame,
      survey=survey,
      rotationAngle_deg=rotationAngle_deg,
      width_height_arcmin=width_height_arcmin,
      shrink=shrink,
      show_plot=show_plot,
      plot_file=plot_file,
      overwrite=overwrite,
      figsize_str=figsize_str,
      title=title,
      percentile=percentile,
      cmap=cmap,
      colors_str=colors_str,
      lws_str=lws_str,
      zorders_str=zorders_str,
      marker_kwargs_str=marker_kwargs_str,
      print_gaia_dr2=print_gaia_dr2,
      gaia_dr2_kwargs_str=gaia_dr2_kwargs_str,
      print_vsx=print_vsx,
      vsx_kwargs_str=vsx_kwargs_str,
      sexagesimal=sexagesimal,
      verbose=verbose
    )
示例#4
0
def mkpy3_tpf_overlay_v6(
        tpf=None,
        frame=0,
        survey='2MASS-J',  # '2MASS-J' or 'DSS2 Red'
        width_height_arcmin=2.0,
        rotationAngle_deg=None,
        shrink=1.0,
        show_plot=True,
        plot_file='mkpy3_plot.png',
        overwrite=False,
        figsize_str='[9,9]',
        title=None,
        percentile=99.0,
        cmap='gray_r',
        colors_str="[None,'cornflowerblue','red']",
        lws_str='[0,3,4]',
        zorders_str='[0,2,4]',
        marker_kwargs_str="{'edgecolor':'yellow', 's':600, 'facecolor':'None',\
    'lw':3, 'zorder':10}",  # or 'None'
        print_gaia_dr2=True,
        gaia_dr2_kwargs_str="{'edgecolor':'cyan', 's':300, 'facecolor':'None',\
    'lw':3, 'zorder':20}",  # or 'None'
        print_vsx=True,
        vsx_kwargs_str="{'s':900, 'color':'lawngreen', 'marker':'x', 'lw':5,\
    'zorder':30}",  # or 'None'
        sexagesimal=False,
        verbose=False):
    '''
Function: mkpy3_tpf_overlay_v6()

Purpose:

Plot a Kepler/K2/TESS TargetPixelFile (TPF) overlay on a sky survey image.

Parameters
----------
tpf : (lightkurve TargetPixelFile object) (optional)
    A lightkurve TargetPixelFile (TPF) object.
    [default: None]
frame : (int) (optional)
    Frame number to use.
    [range: 0 to number of cadences in the TPF minus 1]
    [default: 0]
survey : (str) (optional)
    A sky survey name.
    [default: '2MASS-J'] [verified: '2MASS-J', 'DSS2 Red']
rotationAngle_deg : (None) or (float) or ('tpf') (optional)
    Angle in degrees to rotate the sky survey image
    [default for Kepler & K2 missions: None]
    [default for TESS mission: 'tpf']
    [example values: None, 12.345, 'tpf']
width_height_arcmin : (float) (optional)
    Width and height of the survey image [arcmin].
    [default: 2.0]
shrink : (float) (optional)
    Survey search radius shrink factor.
    [range: 0.0 to 1.0]
    [default: 1.0]
show_plot : (bool) (optional)
    If True, show the plot.
    [default=True]
plot_file : (str) (optional)
    Filename of the output plot.
    [default: 'mkpy3_plot.png']
overwrite : (bool) (optional)
    If True, overwrite ("clobber") an existing output file.
    If False, do *not* create output file when plot_file != 'mkpy3_plot.png'.
    [default: False]
figsize_str : (str) (optional)
    A string of a 2-element list of figure width and height [Matplotlib].
    [default: '[9,9]']
title : (str) (optional)
    Title of the plot.
    If None, a title will be created.
    An empty string ('') will produce a blank title.
    [default: None]
percentile : (float) (optional)
    Percentile [percentage of pixels to keep] used to set the colorbar.
    [range: 0.0 to 100.0]
    [default: 99.0]
cmap : (str) (optional)
    Colormap name [Matplotlib].
    [default: 'gray_r']
colors_str : (str) (optional)
    A string of a 3-item list of overlay color names [Matplotlib].
    [default: "['None','cornflowerblue','red']"]
lws_str : (str) (optional)
    A string of a 3-item list of overlay line widths [Matplotlib].
    [default: '[0,3,4]']
zorders_str : (str) (optional)
    A string of a 3-item list of overlay zorder values [Matplotlib].
    [default: '[0,1,2]']
marker_kwargs_str : (str) (optional)
    A string of a dictionary of arguments for ax.scatter() [Matplotlib].
    The target is marked according to the kwarg values.
    If set to None, the target is *not* marked.
    [default: "{'edgecolor':'yellow', 's':600, 'facecolor':'None', 'lw':3,
    'zorder':10}"]
print_gaia_dr2 : (bool) (optional)
    If True, print the GAIA DR2 catalog results.
    [default=True]
gaia_dr2_kwargs_str : (str) (optional)
    A string of a dictionary of arguments for ax.scatter() [Matplotlib].
    GAIA DR2 stars are marked accordinbg to the kwarg values.
    If set to None, no GAIA DR2 data are shown and plotted.
    [default: "{'edgecolor':'cyan', 's':300, 'facecolor':'None', 'lw':3,
    'zorder':20}"]
print_vsx : (bool) (optional)
    If True, print the VSX catalog results.
vsx_kwargs_str : (str) (optional)
    A string of a dictionary of arguments for ax.scatter() [Matplotlib].
    VSX varaible stars are marked accordinbg to the kwarg values.
    If set to None, no VSX data are shown and plotted.
    [default: "{'s':900, 'color':'lawngreen', 'marker':'x', 'lw':5,
    'zorder':30}"]
sexagesimal : (bool) (optional)
    If True, print catalog positions as sexagesimal [hms dms].
    [default=False]
verbose : (bool) (optional)
    If True, print extra information.
    [default: False]

Returns
-------
ax : (matplotlib axes object) or (None)
    Returns a matplotlib axes object *if* show_plot is False *else* None .

# Kenneth Mighell
# Kepler Support Scientist
# NASA Ames Research Center / SETI Institute
    '''
    import matplotlib.pyplot as plt
    import numpy as np
    import copy as cp
    from astropy.coordinates import SkyCoord
    import astropy.units as u
    import ast
    import sys
    import inspect
    #
    import reproject as rp  # pip install reproject
    #
    import lightkurve as lk
    lk.log.setLevel('INFO')
    #
    import mkpy3

    func_ = inspect.stack()[0][3]  # function name

    # assert(tpf is not None)
    if (tpf is None):
        tpf = lk.search_targetpixelfile(target='kepler-138b',
                                        mission='kepler',
                                        quarter=10).download(quality_bitmask=0)
        # ^--- exoplanet Kelper-138b is "KIC 7603200"
    # pass:if

    if ((rotationAngle_deg is None) and (tpf.mission.lower() == 'tess')):
        rotationAngle_deg = 'tpf'
    # pass:if

    title_ = title
    figsize = ast.literal_eval(figsize_str)
    colors = ast.literal_eval(colors_str)
    lws = ast.literal_eval(lws_str)
    zorders = ast.literal_eval(zorders_str)
    marker_kwargs = ast.literal_eval(marker_kwargs_str)
    gaia_dr2_kwargs = ast.literal_eval(gaia_dr2_kwargs_str)
    vsx_kwargs = ast.literal_eval(vsx_kwargs_str)

    assert (shrink >= 0.0)
    assert ((percentile > 0.0) and (percentile <= 100.0))
    assert (isinstance(figsize, list))
    assert (len(figsize) == 2)
    assert (isinstance(colors, list))
    assert (len(colors) == 3)
    assert (isinstance(lws, list))
    assert (len(lws) == 3)
    assert (isinstance(zorders, list))
    assert (len(zorders) == 3)
    assert (isinstance(marker_kwargs, dict) or (marker_kwargs is None))
    assert (isinstance(gaia_dr2_kwargs, dict) or (gaia_dr2_kwargs is None))
    assert (isinstance(vsx_kwargs, dict) or (vsx_kwargs is None))

    if (verbose):
        print(func_, '=func_')
        print(tpf, '=tpf')
        print(frame, '=frame')
        print(survey, '=survey')
        print(rotationAngle_deg, '=rotationAngle_deg')
        print('^---', type(rotationAngle_deg),
              '=type(rotationAngle_deg)  ***INFO***')
        print(width_height_arcmin, '=width_height_arcmin')
        print(shrink, '=shrink')
        print(show_plot, '=show_plot')
        print(plot_file, '=plot_file')
        print(overwrite, '=overwrite')
        print(figsize, '=figsize')
        print(title_, '=title')
        print(percentile, '=percentile')
        print(cmap, '=cmap')
        print(colors, '=colors')
        print(lws, '=lws')
        print(zorders, '=zorders')
        print(marker_kwargs, '=marker_kwargs')
        print(print_gaia_dr2, '=print_gaia_dr2')
        print(gaia_dr2_kwargs, '=gaia_dr2_kwargs')
        print(print_vsx, '=print_vsx')
        print(vsx_kwargs, '=vsx_kwargs')
        print(sexagesimal, '=sexagesimal')
        print(verbose, '=verbose')
    # pass:if

    ra_deg = tpf.ra
    dec_deg = tpf.dec
    if (verbose):
        print()
        print(ra_deg, '=ra_deg')
        print(dec_deg, '=dec_deg')
    # pass:if

    tpf_positionAngle_deg,\
      tpf_n_pa_deg,\
      tpf_mirrored,\
      tpf_north_top_half,\
      tpf_east_left_half \
      = mkpy3__wcs_compass_check_v2(wcs=tpf.wcs, verbose=verbose)
    if (verbose):
        print(tpf_positionAngle_deg, '=tpf_positionAngle_deg')
        print(tpf_n_pa_deg, '=tpf_n_pa_deg')
        print(tpf_mirrored, '=tpf_mirrored')
        print(tpf_north_top_half, '=tpf_north_top_half')
        print(tpf_east_left_half, '=tpf_east_left_half')
    # pass:if

    # get survey image data
    # survey = '2MASS-J'  # 'DSS2 Red' # hard-wired options
    survey_hdu, survey_hdr, survey_data, survey_wcs, survey_cframe = \
        mkpy3.mkpy3_finder_chart_survey_fits_image_get_v1(
          ra_deg, dec_deg,
          radius_arcmin=width_height_arcmin, survey=survey, verbose=verbose)

    survey_positionAngle_deg,\
      survey_n_pa_deg,\
      survey_mirrored,\
      survey_north_top_half,\
      survey_east_left_half \
      = mkpy3__wcs_compass_check_v2(wcs=survey_wcs, verbose=verbose)
    if (verbose):
        print(survey_positionAngle_deg, '=survey_positionAngle_deg')
        print(survey_n_pa_deg, '=survey_n_pa_deg')
        print(survey_mirrored, '=survey_mirrored')
        print(survey_north_top_half, '=survey_north_top_half')
        print(survey_east_left_half, '=survey_east_left_half')
    # pass:if

    survey_rotate_deg = None
    rotate_deg = cp.deepcopy(rotationAngle_deg)
    skip = (rotate_deg is None) or (rotate_deg == 0.0)
    if (not skip):
        print('\n***** ROTATE IMAGE *****:')
        if (verbose):
            print(rotationAngle_deg, '=rotationAngle_deg')
            print('^---', type(rotationAngle_deg), '=type(rotationAngle_deg)')
        # pass:if
        is_number = isinstance(rotationAngle_deg, (float, int))
        if (is_number):
            if (verbose):
                print('rotationAngle_deg is a number!')
            # pass:if
        else:
            is_str = isinstance(rotationAngle_deg, str)
            if (is_str):
                if (verbose):
                    print('rotationAngle_deg is a string')
                # pass:if
            else:
                print(type(rotationAngle_deg), '=type(rotationAngle_deg')
                print('^--- can not process this type of object')
                sys.exit(1)
            # pass:if
            if (rotationAngle_deg !=
                    'tpf'):  # a 3-char str with a value of tpf
                print(rotationAngle_deg, '=rotationAngle_deg')
                print(
                    "^--- ***ERROR*** BAD STRING VALUE!  ONLY 'tpf' IS ALLOWED!"
                )
                sys.exit(1)
            # pass:if
        # pass:if
        if (rotationAngle_deg == 'tpf'):  # a 3-char str with a value of tpf
            tpf_pa_deg = tpf_n_pa_deg  # less reliable: tpf_positionAngle_deg
            if (not tpf_east_left_half):
                tpf_pa_deg *= (-1.0)
            # pass:if
            tpf_pa_fabs_deg = np.fabs(tpf_pa_deg)
            tpf_pa_sign = np.sign(tpf_pa_deg)
            if (verbose):
                print('[!]', tpf_pa_deg, '=tpf_pa_deg')
                print('[!]', tpf_pa_fabs_deg, '=tpf_pa_fabs_deg')
                print('[!]', tpf_pa_sign, '=tpf_pa_sign')
            # pass:if
            reverse = (-1.0)
            if (tpf_pa_fabs_deg <= 90.0):
                rotate_deg = reverse * tpf_pa_deg
                if (verbose):
                    print('[!]', rotate_deg,
                          '= rotate_deg = reverse * tpf_pa_deg')
                # pass:if
            else:
                rotate_deg = reverse * tpf_pa_sign * (180.0 - tpf_pa_fabs_deg)
                if (verbose):
                    print(
                        '[!]', rotate_deg,
                        '= reverse * tpf_pa_sign * (180.0 - tpf_pa_fabs_deg)')
                # pass:if
            is_number = True
        # pass:if
        survey_rotate_deg = rotate_deg
        if (verbose):
            print('%.3f =survey_rotate_deg [deg] : rotation angle '
                  '<------------' % survey_rotate_deg)
        # pass:if
        if (is_number):
            # modify survey World Coordinate System (WCS)
            wcs = cp.deepcopy(survey_wcs)
            theta = np.deg2rad(rotate_deg)
            # create rotation matrix
            rotation_matrix = np.matrix([[np.cos(theta), -np.sin(theta)],
                                         [np.sin(theta),
                                          np.cos(theta)]])
            # adjust the survey WCS pc coefficients
            rotated_pc = np.dot(rotation_matrix, wcs.wcs.pc)
            # update the survey WCS pc coefficients
            wcs.wcs.pc = rotated_pc
            # rotate survey image data using updated WCS
            reprojected_survey_data, reprojected_footprint = \
              rp.reproject_interp(
                survey_hdu, wcs, shape_out=survey_data.shape)
            # aliases
            survey_data = reprojected_survey_data
            survey_wcs = wcs
            #
            survey_positionAngle_deg,\
              survey_n_pa_deg,\
              survey_mirrored,\
              survey_north_top_half,\
              survey_east_left_half \
              = mkpy3__wcs_compass_check_v2(wcs=survey_wcs, verbose=verbose)
            print(survey_rotate_deg, '=survey_rotate_deg')
            if (verbose):
                print(survey_positionAngle_deg,
                      '=survey_positionAngle_deg [revised]')
                print(survey_n_pa_deg, '=survey_n_pa_deg [revised]')
                print(survey_mirrored, '=survey_mirrored [revised]')
                print(survey_north_top_half,
                      '=survey_north_top_half [revised]')
                print(survey_east_left_half,
                      '=survey_east_left_half [revised]')
            # pass:if
        # pass:if
    # pass:if

    # create a matplotlib figure object
    plt.figure(figsize=figsize)

    # create a matplotlib axis object with right ascension and declination axes
    ax = plt.subplot(projection=survey_wcs)

    # HACK: BEGIN : *NEW* attributes of the axis
    ax.tpf_positionAngle_deg = tpf_positionAngle_deg
    ax.tpf_n_pa_deg = tpf_n_pa_deg
    ax.tpf_mirrored = tpf_mirrored
    ax.tpf_north_top_half = tpf_north_top_half
    ax.tpf_east_left_half = tpf_east_left_half
    ax.survey_rotationAngle_deg = rotationAngle_deg
    ax.survey_rotate_deg = survey_rotate_deg
    ax.survey_positionAngle_deg = survey_positionAngle_deg
    ax.survey_n_pa_deg = survey_n_pa_deg
    ax.survey_mirrored = survey_mirrored
    ax.survey_north_top_half = survey_north_top_half
    ax.survey_east_left_half = survey_east_left_half
    # HACK: END

    # show the survey image
    mkpy3.mkpy3_finder_chart_image_show_v1(ax=ax,
                                           image_data=survey_data,
                                           percentile=percentile,
                                           cmap=cmap,
                                           verbose=verbose)

    # show the TPF overlay
    mkpy3.mkpy3_finder_chart_tpf_overlay_v6(ax=ax,
                                            survey_wcs=survey_wcs,
                                            tpf=tpf,
                                            frame=frame,
                                            colors=colors,
                                            lws=lws,
                                            zorders=zorders,
                                            verbose=verbose)

    # add suptitle
    if (title_ is None):
        hdr = tpf.hdu[0].header  # alias
        try:  # Kepler?
            quarter = hdr['quarter']
            tag3_ = ('Quarter %02d' % quarter)
            tag2_ = hdr['object']
            tag1_ = 'Kepler'
            title_ = tag2_ + ' : ' + tag1_ + ' : ' + tag3_
        except Exception:
            try:  # K2?
                campaign = hdr['campaign']
                tag3_ = ('Campaign %02d' % campaign)
                tag2_ = hdr['object']
                tag1_ = 'K2'
                title_ = tag2_ + ' : ' + tag1_ + ' : ' + tag3_
            except Exception:  # TESS!
                sector = hdr['sector']
                tag2_ = ('Sector %02d' % sector)
                tag1_ = 'TESS'
                title_ = tag1_ + ' : ' + tag2_
            # pass:try
        # pass:try
        assert (title_ is not None)
    # pass:if
    plt.suptitle(title_, size=25)

    # option: mark the target
    if (isinstance(marker_kwargs, dict)):
        ax.scatter(ra_deg * u.deg,
                   dec_deg * u.deg,
                   transform=ax.get_transform(survey_cframe),
                   **marker_kwargs)

    # CATALOGS:BEGIN  =========================================================

    ra_deg = tpf.ra
    dec_deg = tpf.dec

    fudge = np.sqrt(2) / 2.0
    radius_arcsec = width_height_arcmin * 60.0 * fudge * shrink
    print()
    print('%.6f =radius_arcsec  (%.6f =shrink)' % (radius_arcsec, shrink))

    # ===== GAIA DR2 CATALOG ==================================================

    proceed = isinstance(gaia_dr2_kwargs, dict) and (shrink > 0.0)
    print(proceed, '=proceed [GAIA2 catalog]')
    while (proceed):

        raj2000, dej2000, sep_arcsec, gaia_dr2_result = \
            mkpy3.mkpy3_vizier_gaia_dr2_cone_get_v2(
              ra_deg=ra_deg, dec_deg=dec_deg,
              radius_arcsec=radius_arcsec, verbose=verbose)
        if (gaia_dr2_result is None):  # nothing found
            print(gaia_dr2_result,
                  '=gaia_dr2_result [***WARNING*** NOTHING FOUND]')
            break
        # pass:if
        if (type(gaia_dr2_kwargs) is dict):
            ax.scatter(raj2000,
                       dej2000,
                       transform=ax.get_transform(survey_cframe),
                       **gaia_dr2_kwargs)
        # pass:if

        # numpy vectors of useful columns
        xra = raj2000  # alias
        yde = dej2000  # alias
        gmag = np.array(gaia_dr2_result['Gmag'])
        src = np.array(gaia_dr2_result['Source'])
        pmra = np.array(gaia_dr2_result['pmRA'])
        pmde = np.array(gaia_dr2_result['pmDE'])
        plx = np.array(gaia_dr2_result['Plx'])
        pmra = np.array(gaia_dr2_result['pmRA'])
        pmde = np.array(gaia_dr2_result['pmDE'])

        print()
        print(print_gaia_dr2, '=print_gaia_dr2')
        if (print_gaia_dr2):
            print('^--- set this keyword argument to False to *not* print',
                  end='')
        else:
            print('^--- set this keyword argument to True to print', end='')
        # pass:if
        print(' the GAIA DR2 catalog results.')
        if (print_gaia_dr2):
            print()
            print()
            print('# GAIA DR2 : Global Astrometric Interferometer for Astrophy'
                  'sics-- Data Release 2')
            print('# n GAIA2_Source             sep    RA_ICRS      DE_ICRS   '
                  '    pmRA     pmDE      Plx     Gmag')
            print('#                       [arcsec]    [deg]        [deg]     '
                  ' [mas/yr] [mas/yr]    [mas]    [mag]')
            for k in range(len(xra)):
                j = k  # idx[k]
                raj = xra[j]
                dej = yde[j]
                gmagj = gmag[j]
                sepj = sep_arcsec[j]
                kk = k + 1
                srcj = src[j]
                pmraj = pmra[j]
                pmdej = pmde[j]
                plxj = plx[j]
                print('%3d %d %8.3f %12.7f %12.7f %8.3f %8.3f %8.3f %8.3f' %
                      (kk, srcj, sepj, raj, dej, pmraj, pmdej, plxj, gmagj))
            #  pass:for

            if (sexagesimal):
                print()
                print('# GAIA DR2 : Global Astrometric Interferometer for Astr'
                      'ophysics -- Data Release 2')
                print('# n GAIA2_Source          RA_ICRS       DE_ICRS      RA'
                      '_ICRS         DE_ICRS')
                print('#                         [deg]         [deg]        [h'
                      'ms]           [dms]')
                for k in range(len(xra)):
                    j = k  # idx[k]
                    xraj = xra[j]
                    ydej = yde[j]
                    gmagj = gmag[j]
                    sc1 = SkyCoord(ra=xraj,
                                   dec=ydej,
                                   frame='icrs',
                                   unit='degree')
                    ra_ = sc1.ra.to_string(u.hour)
                    dec_ = sc1.dec
                    sepj = sep_arcsec[j]
                    kk = k + 1
                    srcj = src[j]
                    print('%3d %d %12.7f %12.7f  %15s %15s' %
                          (kk, srcj, xraj, ydej, ra_, dec_))
                # pass:for
            # pass:if
        # pass:if
        break
    # pass:while

    # ===== VSX CATALOG =======================================================

    proceed = isinstance(vsx_kwargs, dict) and (shrink > 0)
    while (proceed):

        raj2000, dej2000, sep_arcsec, vsx_result = \
          mkpy3.mkpy3_vizier_vsx_cone_get_v2(
            ra_deg=ra_deg, dec_deg=dec_deg,
            radius_arcsec=radius_arcsec, verbose=verbose)
        if (vsx_result is None):  # nothing found
            print(vsx_result, '=vsx_result [***WARNING*** NOTHING FOUND]')
            break
        # pass:if
        if (type(vsx_kwargs) is dict):
            ax.scatter(raj2000,
                       dej2000,
                       transform=ax.get_transform(survey_cframe),
                       **vsx_kwargs)
        # pass:if

        # numpy vectors of useful columns
        name = np.array(vsx_result['Name'], dtype=np.str)
        mag_max = np.array(vsx_result['max'])
        mag_min = np.array(vsx_result['min'])
        period = np.array(vsx_result['Period'])
        vsx_type = np.array(vsx_result['Type'], dtype=np.str)

        print()
        print(print_vsx, '=print_vsx')
        if (print_vsx):
            print('^--- set this keyword argument to False to *not* print',
                  end='')
        else:
            print('^--- set this keyword argument to True to print', end='')
        # pass:if
        print(' the VSX catalog results.')
        if (print_vsx):
            print()
            print()
            print('# VSX : AAVSO International Variable Star indeX')
            print('# n      sep    RAJ2000      DEJ2000       Period     '
                  'VSX_max   VSX_min  VSX_Name      VSX_Type')
            print('#   [arcsec]    [deg]        [deg]         [days]     '
                  '[mag]     [mag]')
            for j in range(raj2000.size):
                k = j + 1
                raj = raj2000[j]
                dej = dej2000[j]
                sepj = sep_arcsec[j]
                pj = period[j]
                mxj = mag_max[j]
                mnj = mag_min[j]
                namej = name[j]
                vsxtypej = vsx_type[j]
                print("%3d %8.3f %12.7f %12.7f %12.6f %9.3f %9.3f '%s' '%s'" %
                      (k, sepj, raj, dej, pj, mxj, mnj, namej, vsxtypej))
            # pass:for

            if (sexagesimal):
                print()
                print('# VSX : AAVSO International Variable Star indeX')
                print('# n   RAJ2000       DEJ2000        RAJ2000        DEJ20'
                      '00')
                print('#     [deg]         [deg]          [hms]          '
                      '[dms]')
                for j in range(raj2000.size):
                    k = j + 1
                    xraj = raj2000[j]
                    ydej = dej2000[j]
                    sc1 = SkyCoord(ra=xraj,
                                   dec=ydej,
                                   frame='icrs',
                                   unit='degree')
                    ra_ = sc1.ra.to_string(u.hour)
                    dec_ = sc1.dec
                    print('%3d %12.7f %12.7f  %15s %15s' %
                          (k, xraj, ydej, ra_, dec_))
                # pass:for
            # pass:if
        # pass:if
        break
    # pass:while

    # =========================================================================
    # CATALOGS: END ===========================================================
    # =========================================================================

    print()
    print(ra_deg, '=ra_deg')
    print(dec_deg, '=dec_deg')
    print()
    print('%d =cadenceno' % (tpf.cadenceno[frame]))
    print(frame, '=frame')

    # reset plotting area to show only the survey image range in X and Y
    nx = survey_data.shape[1]
    ny = survey_data.shape[0]
    ax.set_xlim(0, nx)
    ax.set_ylim(0, ny)

    # adjust the plot margins
    plt.subplots_adjust(left=0.2, right=0.9, top=0.9, bottom=0.2)

    # match orienttion of tpf.plot() graph ====================================
    ax.xaxis_inverted = False
    ax.yaxis_inverted = False
    if (rotationAngle_deg == 'tpf'):  # a 3-char str with a value of tpf
        if (ax.survey_east_left_half != ax.tpf_east_left_half):
            ax.invert_xaxis()
            ax.xaxis_inverted = True
        # pass:if
        if (ax.survey_north_top_half != ax.tpf_north_top_half):
            ax.invert_yaxis()
            ax.yaxis_inverted = True
        # pass:if
    # pass:if
    # =========================================================================

    if (plot_file == ''):
        plot_file = None
    if (plot_file is not None):
        if (plot_file != 'mkpy3_plot.png'):
            mkpy3.mkpy3_util_check_file_exists(plot_file, overwrite)
        plt.savefig(plot_file, dpi=300)  # , bbox_inches = "tight")
        print('\n%s <--- plot_file written\n' % (plot_file))
    # pass:if

    if (show_plot):
        plt.ioff()
        plt.show()
        ax = None
    # pass:if

    print()
    print('DONE:', func_)
    print()

    return ax