"""
Python class for the NGC 1068 PCA project

requirements:
CASA Version 5.4.0-70, ananlysisUtils, astropy

data:
ALMA main Band 3 data 2013.1.00279.S
ALMA supplements      2011.0.00061.S
                      2012.1.00657.S
                      2013.1.00060.S
                      2015.1.00960.S
                      2017.1.00586.S
                      2018.1.01506.S
                      2018.1.01684.S
                      2019.1.00130.S
imaging script        all processed by phangs pipeline v2
                      Leroy et al. 2021, ApJS, 255, 19 (https://ui.adsabs.harvard.edu/abs/2021ApJS..255...19L)
ancillary MUSE FITS   Mingozzi et al. 2019, A&A, 622, 146 (https://ui.adsabs.harvard.edu/abs/2019A%26A...622A.146M)
                      SIII/SII ratio map (ionization parameter), ionized gas density, AV maps
                      http://cdsarc.u-strasbg.fr/viz-bin/qcat?J/A+A/622/A146

usage:
> import os
> from scripts_n1068_hex_pca import ToolsPCA as tools
>
> # key
> tl = tools(
>     refresh     = False,
>     keyfile_gal = "/home02/saitots/myUtils/keys_projects/galkey_ngc1068.txt",
>     keyfile_fig = "/home02/saitots/myUtils/keys_projects/key_n1068_hex_pca.txt",
>     )
>
> # main
> tl.run_ngc1068_pca(
>     # analysis
>     do_prepare             = True,
>     do_sampling            = True,
>     do_pca                 = True,
>     # plot
>     plot_hexmap_mom0       = True,
>     plot_envmask           = True,
>     plot_hexmap_pca        = True,
>     plot_hexmap_pca_podium = True,
>     plot_median_line_graph = True,
>     do_imagemagick         = True,
>     # supplement
>     plot_supplements       = True,
>     do_imagemagick_sub     = True,
>     )
>
> os.system("rm -rf *.last")

paper drafts:
Date         Filename                        To
2021-12-21   draft_v0_211221.zip             Takano-san,Nakajima-san,Harada-san,Tamura-san
2022-02-18   draft_v1_220218.zip             Editage (English proofreading)
2022-05-12   draft_v2_submitted_220512.zip   ApJ

history:
2021-11-10   created
2021-11-14   2DPCA analysis for mom0 maps
2021-11-15   start drafting
2021-11-22   implement LOWESS and bootstrapped standard deviation
2021-12-21   circulate v0 draft to the paper team
2022-01-25   replace radial plot with line graph
2022-02-18   send to Editage (English proofreading)
2022-03-03   circulate v1 draf to all co-Is
2022-04-24   revise figures
2022-05-12   submit to ApJ
2022-06-20   add measurements of rms in K, typical S/N ratio in hex_sampling
2022-07-14   accepted!
2022-07-26   create molecular richness map
Toshiki Saito@Nichidai/NAOJ
"""

import os, sys, glob
import numpy as np

from mycasa_sampling import *
from mycasa_lowess import *
from mycasa_tasks import *
from mycasa_plots import *
from mycasa_pca import *

############
# ToolsPCA #
############
class ToolsPCA():
    """
    Class for the NGC 1068 PCA project.
    """

    ############
    # __init__ #
    ############

    def __init__(
        self,
        keyfile_fig  = None,
        keyfile_gal  = None,
        refresh      = False,
        delete_inter = True,
        ):
        # initialize keys
        self.keyfile_gal = keyfile_gal
        self.keyfile_fig = keyfile_fig

        # intialize task
        self.refresh      = refresh
        self.delete_inter = delete_inter
        self.taskname     = None

        # initialize directories
        self.dir_raw      = None
        self.dir_ready    = None
        self.dir_other    = None
        self.dir_products = None
        self.fig_dpi      = 200

        # import parameters
        if keyfile_fig is not None:
            self.modname = "ToolsPCA."
            self._set_dir()            # directories
            self._set_input_fits()     # input maps
            self._set_output_fits()    # output maps
            self._set_input_param()    # input parameters
            self._set_output_txt_png() # output txt and png

    def _set_dir(self):
        """
        """

        self.dir_proj     = self._read_key("dir_proj")
        self.dir_raw      = self.dir_proj + self._read_key("dir_raw")
        self.dir_ready    = self.dir_proj + self._read_key("dir_ready")
        self.dir_other    = self.dir_proj + self._read_key("dir_other")
        self.dir_products = self.dir_proj + self._read_key("dir_products")
        self.dir_final    = self.dir_proj + self._read_key("dir_final")

        self._create_dir(self.dir_ready)
        self._create_dir(self.dir_products)
        self._create_dir(self.dir_final)

    def _set_input_fits(self):
        """
        """

        self.map_av         = self.dir_other + self._read_key("map_av")
        self.map_ionization = self.dir_other + self._read_key("map_ionization")
        self.maps_mom0      = glob.glob(self.dir_raw + self._read_key("maps_mom0"))
        self.maps_emom0     = glob.glob(self.dir_raw + self._read_key("maps_emom0"))
        self.maps_mom0.sort()
        self.maps_emom0.sort()

    def _set_output_fits(self):
        """
        """

        self.outmap_mom0   = self.dir_ready + self._read_key("outmaps_mom0")
        self.outfits_mom0  = self.dir_ready + self._read_key("outfits_maps_mom0")
        self.outmap_emom0  = self.dir_ready + self._read_key("outmaps_emom0")
        self.outfits_emom0 = self.dir_ready + self._read_key("outfits_maps_emom0")

    def _set_input_param(self):
        """
        """

        # ngc1068 properties
        self.ra_agn    = float(self._read_key("ra_agn", "gal").split("deg")[0])
        self.dec_agn   = float(self._read_key("dec_agn", "gal").split("deg")[0])
        self.scale_pc  = float(self._read_key("scale", "gal"))
        self.scale_kpc = self.scale_pc / 1000.

        self.beam      = 2.14859173174056 # 150pc in arcsec
        self.snr_mom   = 4.0
        self.r_cnd     = 3.0 * self.scale_pc / 1000. # kpc
        self.r_cnd_as  = 3.0
        self.r_sbr     = 10.0 * self.scale_pc / 1000. # kpc
        self.r_sbr_as  = 10.0
        self.gridsize  = 27 # int(np.ceil(self.r_sbr_as*2/self.beam))

    def _set_output_txt_png(self):
        """
        """

        # output txt and png
        self.table_hex_obs            = self.dir_ready + self._read_key("table_hex_obs")
        self.table_hex_pca_mom0       = self.dir_ready + self._read_key("table_hex_pca_mom0")
        self.table_hex_pca_r13co      = self.dir_ready + self._read_key("table_hex_pca_r13co")
        self.table_hex_pca_rhcn       = self.dir_ready + self._read_key("table_hex_pca_rhcn")

        self.outpng_pca_mom0          = self.dir_products + self._read_key("outpng_pca_mom0")
        self.outpng_pca_r13co         = self.dir_products + self._read_key("outpng_pca_r13co")
        self.outpng_pca_rhcn          = self.dir_products + self._read_key("outpng_pca_rhcn")

        self.outpng_mom0              = self.dir_products + self._read_key("outpng_mom0")
        self.outpng_12co10_oveall     = self.outpng_mom0.replace("???","12co10_overall")

        self.outpng_pca_hexmap        = self.dir_products + self._read_key("outpng_pca_hexmap")
        self.outpng_pca_scatter       = self.dir_products + self._read_key("outpng_pca_scatter")
        self.outpng_pca_hexmap_r13co  = self.dir_products + self._read_key("outpng_pca_hexmap_r13co")
        self.outpng_pca_scatter_r13co = self.dir_products + self._read_key("outpng_pca_scatter_r13co")

        outpng_pca1_mom0_podium       = self.dir_products + self._read_key("outpng_pca1_mom0_podium")
        self.outpng_pca1_mom0_1st     = outpng_pca1_mom0_podium.replace("???","1st")
        self.outpng_pca1_mom0_2nd     = outpng_pca1_mom0_podium.replace("???","2nd")
        self.outpng_pca1_mom0_3rd     = outpng_pca1_mom0_podium.replace("???","3rd")
        self.outpng_pca1_mom0_4th     = outpng_pca1_mom0_podium.replace("???","4th")

        outpng_pca2_mom0_podium       = self.dir_products + self._read_key("outpng_pca2_mom0_podium")
        self.outpng_pca2_mom0_1st     = outpng_pca2_mom0_podium.replace("???","1st")
        self.outpng_pca2_mom0_2nd     = outpng_pca2_mom0_podium.replace("???","2nd")
        self.outpng_pca2_mom0_3rd     = outpng_pca2_mom0_podium.replace("???","3rd")
        self.outpng_pca2_mom0_4th     = outpng_pca2_mom0_podium.replace("???","4th")

        outpng_pca1_ratio_podium      = self.dir_products + self._read_key("outpng_pca1_ratio_podium")
        self.outpng_pca1_ratio_1st    = outpng_pca1_ratio_podium.replace("???","1st")
        self.outpng_pca1_ratio_2nd    = outpng_pca1_ratio_podium.replace("???","2nd")
        self.outpng_pca1_ratio_3rd    = outpng_pca1_ratio_podium.replace("???","3rd")
        self.outpng_pca1_ratio_4th    = outpng_pca1_ratio_podium.replace("???","4th")

        outpng_pca2_ratio_podium      = self.dir_products + self._read_key("outpng_pca2_ratio_podium")
        self.outpng_pca2_ratio_1st    = outpng_pca2_ratio_podium.replace("???","1st")
        self.outpng_pca2_ratio_2nd    = outpng_pca2_ratio_podium.replace("???","2nd")
        self.outpng_pca2_ratio_3rd    = outpng_pca2_ratio_podium.replace("???","3rd")
        self.outpng_pca2_ratio_4th    = outpng_pca2_ratio_podium.replace("???","4th")

        self.outpng_radial1           = self.dir_products + self._read_key("outpng_radial1")
        self.outpng_radial2           = self.dir_products + self._read_key("outpng_radial2")
        self.outpng_radial3           = self.dir_products + self._read_key("outpng_radial3")

        self.outpng_line_graph        = self.dir_products + self._read_key("outpng_line_graph")
        self.outpng_envmask           = self.dir_products + self._read_key("outpng_envmask")

        # final
        self.final_overall            = self.dir_final + self._read_key("final_overall")
        self.final_mom0               = self.dir_final + self._read_key("final_mom0")
        self.final_pca_mom0           = self.dir_final + self._read_key("final_pca_mom0")
        self.final_pca_r13co          = self.dir_final + self._read_key("final_pca_r13co")
        self.final_pca_mom0_podium    = self.dir_final + self._read_key("final_pca_mom0_podium")
        self.final_pca_ratio_podium   = self.dir_final + self._read_key("final_pca_ratio_podium")
        self.final_hex_radial         = self.dir_final + self._read_key("final_hex_radial")
        self.final_line_graph         = self.dir_final + self._read_key("final_line_graph")

        self.appendix_pca_mom0        = self.dir_final + self._read_key("appendix_pca_mom0")

        self.box_map                  = self._read_key("box_map")
        self.box_map_noxlabel         = self._read_key("box_map_noxlabel")
        self.box_map_noylabel         = self._read_key("box_map_noylabel")
        self.box_map_noxylabel        = self._read_key("box_map_noxylabel")

        # extra
        self.outpng_extra_richness    = self.dir_products + self._read_key("outpng_extra_richness")

    ###################
    # run_ngc1068_pca #
    ###################

    def run_ngc1068_pca(
        self,
        # analysis
        do_prepare             = False,
        do_sampling            = False,
        do_pca                 = False,
        # plot figures in paper
        plot_hexmap_mom0       = False,
        plot_envmask           = False,
        plot_hexmap_pca        = False,
        plot_hexmap_pca_podium = False,
        plot_median_line_graph = False,
        do_imagemagick         = False,
        # supplement
        plot_supplements       = False,
        do_imagemagick_sub     = False,
        # referee comments
        referee_meas_rms_snr   = False,
        # extra
        plot_mol_richness      = False,
        ):
        """
        This method runs all the methods which will create figures in the paper.
        """

        # analysis
        if do_prepare==True:
            self.align_maps()

        if do_sampling==True:
            self.hex_sampling()

        if do_pca==True:
            self.run_hex_pca(output=self.outpng_pca_mom0,outtxt=self.table_hex_pca_mom0,reverse=True)
            #self.run_hex_pca(output=self.outpng_pca_rhcn,outtxt=self.table_hex_pca_rhcn,denom="hcn10",reverse=True)
            #self.run_hex_pca(output=self.outpng_pca_r13co,outtxt=self.table_hex_pca_r13co,denom="13co10",reverse=True)

        # plot figures in paper
        if plot_hexmap_mom0==True:
            self.plot_hexmap_mom0()

        if plot_envmask==True:
            self.plot_envmask()

        if plot_hexmap_pca==True:
            self.plot_hexmap_pca()

        if plot_hexmap_pca_podium==True:
            self.plot_hexmap_pca_ratio_podium()

        if plot_median_line_graph==True:
            self.plot_max_line_graph(denom="co10",ylim=[-2.2,0.9])
            #self.plot_max_line_graph(denom="hcn10",ylim=[-1.8,2.0])

        if do_imagemagick==True:
            self.immagick_figures()

        # supplement
        if plot_supplements==True:
            self.plot_radial()
            self.plot_hexmap_pca_podium()
            self.plot_hexmap_ratio(denom="13co10")
            self.plot_hexmap_ratio(denom="hcn10")

        if do_imagemagick_sub==True:
            self.immagick_figures_sub()

        if referee_meas_rms_snr==True:
            self.referee_meas_rms_snr()

        # extra
        if plot_mol_richness==True:
            self.plot_mol_richness()

    ####################
    # immagick_figures #
    ####################

    def immagick_figures(
        self,
        delin                      = False,
        do_all                     = False,
        do_final_overall           = False, # Figure 1
        do_final_mom0              = True, # Figure 2
        do_final_pca_mom0          = False, # Figure 3
        do_final_pca1_ratio_podium = False, # Figure 4
        do_final_line_graph        = False, # Figure 5
        do_appendix_pcs            = False, # Figure A
        ):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.outpng_pca_hexmap.replace("???","1"),taskname)

        if do_all==True:
            do_final_overall           = True
            do_final_mom0              = True
            do_final_pca_mom0          = True
            do_final_pca1_ratio_podium = True
            do_final_line_graph        = True

        if do_final_overall==True:
            print("#####################")
            print("# create final_mom0 #")
            print("#####################")

            combine_two_png(
                self.outpng_12co10_oveall,
                self.outpng_envmask,
                self.final_overall,
                self.box_map,
                self.box_map,
                delin=delin,
                )

        if do_final_mom0==True:
            print("#####################")
            print("# create final_mom0 #")
            print("#####################")

            # panel 1
            combine_two_png(
                self.outpng_mom0.replace("???","h13cn10"),
                self.outpng_mom0.replace("???","cch10"),
                self.final_mom0+"_tmp1.png",
                self.box_map_noylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_mom0.replace("???","hcn10"),
                self.outpng_mom0.replace("???","hcop10"),
                self.final_mom0+"_tmp2.png",
                self.box_map_noxylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.final_mom0+"_tmp1.png",
                self.final_mom0+"_tmp2.png",
                self.final_mom0+"_panel1.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                )

            # panel 2
            combine_two_png(
                self.outpng_mom0.replace("???","hnc10"),
                self.outpng_mom0.replace("???","hc3n109"),
                self.final_mom0+"_tmp1.png",
                self.box_map_noylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_mom0.replace("???","n2hp10"),
                self.outpng_mom0.replace("???","ch3oh21"),
                self.final_mom0+"_tmp2.png",
                self.box_map_noxylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.final_mom0+"_tmp1.png",
                self.final_mom0+"_tmp2.png",
                self.final_mom0+"_panel2.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                )

            # panel 3
            combine_two_png(
                self.outpng_mom0.replace("???","cs21"),
                self.outpng_mom0.replace("???","hc3n1110"),
                self.final_mom0+"_tmp1.png",
                self.box_map_noylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_mom0.replace("???","hc3n1211"),
                self.outpng_mom0.replace("???","c18o10"),
                self.final_mom0+"_tmp2.png",
                self.box_map_noxylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.final_mom0+"_tmp1.png",
                self.final_mom0+"_tmp2.png",
                self.final_mom0+"_panel3.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                )

            # panel 4
            combine_two_png(
                self.outpng_mom0.replace("???","13co10"),
                self.outpng_mom0.replace("???","cn10l"),
                self.final_mom0+"_tmp1.png",
                self.box_map_noylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_mom0.replace("???","cn10h"),
                self.outpng_mom0.replace("???","co10"),
                self.final_mom0+"_tmp2.png",
                self.box_map_noxylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.final_mom0+"_tmp1.png",
                self.final_mom0+"_tmp2.png",
                self.final_mom0+"_panel4.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                )

            # panel 5
            combine_two_png(
                self.outpng_mom0.replace("???","ci10"),
                self.outpng_mom0.replace("???","siiisii_ratio"),
                self.final_mom0+"_panel5.png",
                self.box_map,
                self.box_map_noxlabel,
                delin=delin,
                )

            # combine
            combine_two_png(
                self.final_mom0+"_panel1.png",
                self.final_mom0+"_panel2.png",
                self.final_mom0+"_panel12.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                axis="column",
                )

            combine_two_png(
                self.final_mom0+"_panel3.png",
                self.final_mom0+"_panel4.png",
                self.final_mom0+"_panel34.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                axis="column",
                )

            combine_two_png(
                self.final_mom0+"_panel12.png",
                self.final_mom0+"_panel34.png",
                self.final_mom0+"_panel1234.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                axis="column",
                )

            combine_two_png(
                self.final_mom0+"_panel1234.png",
                self.final_mom0+"_panel5.png",
                self.final_mom0,
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                axis="column",
                )

        if do_final_pca_mom0==True:
            print("#########################")
            print("# create final_pca_mom0 #")
            print("#########################")

            combine_two_png(
                self.outpng_pca_hexmap.replace("???","1"),
                self.outpng_pca_hexmap.replace("???","2"),
                self.final_pca_mom0+"_tmp1.png",
                self.box_map,
                self.box_map,
                delin=delin,
                )
            combine_two_png(
                self.outpng_pca_scatter,
                self.final_pca_mom0+"_tmp1.png",
                self.final_pca_mom0,
                self.box_map,
                "100000x100000+0+0",
                axis="column",
                delin=delin,
                )
            os.system("rm -rf " + self.final_pca_mom0 + "_tmp1.png")

        if do_final_pca1_ratio_podium==True:
            print("##################################")
            print("# create final_pca1_ratio_podium #")
            print("##################################")

            # pca1 mom0
            combine_two_png(
                self.outpng_pca1_ratio_1st,
                self.outpng_pca1_ratio_2nd,
                self.final_pca_ratio_podium+"_tmp1.png",
                self.box_map_noylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_pca1_ratio_3rd,
                self.outpng_pca1_ratio_4th,
                self.final_pca_ratio_podium+"_tmp2.png",
                self.box_map_noxylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.final_pca_ratio_podium+"_tmp1.png",
                self.final_pca_ratio_podium+"_tmp2.png",
                self.final_pca_ratio_podium+"_pca1.png",
                "10000x10000+0+0",
                "10000x10000+0+0",
                delin=True,
                )

            combine_two_png(
                self.outpng_pca2_ratio_1st,
                self.outpng_pca2_ratio_2nd,
                self.final_pca_ratio_podium+"_tmp1.png",
                self.box_map,
                self.box_map_noxlabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_pca2_ratio_3rd,
                self.outpng_pca2_ratio_4th,
                self.final_pca_ratio_podium+"_tmp2.png",
                self.box_map_noxlabel,
                self.box_map_noxlabel,
                delin=delin,
                )
            combine_two_png(
                self.final_pca_ratio_podium+"_tmp1.png",
                self.final_pca_ratio_podium+"_tmp2.png",
                self.final_pca_ratio_podium+"_pca2.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                )

            # combine
            combine_two_png(
                self.final_pca_ratio_podium+"_pca1.png",
                self.final_pca_ratio_podium+"_pca2.png",
                self.final_pca_ratio_podium,
                "100000x100000+0+0",
                "100000x100000+0+0",
                axis="column",
                delin=True,
                )

        if do_final_line_graph==True:
            print("##############################")
            print("# create do_final_line_graph #")
            print("##############################")

            immagick_crop(
                self.outpng_line_graph.replace(".png","_co10.png"),
                self.final_line_graph,
                "100000x100000+0+0",
                delin=delin,
                )

            """
            combine_two_png(
                self.outpng_line_graph.replace(".png","_co10.png"),
                self.outpng_line_graph.replace(".png","_hcn10.png"),
                self.final_line_graph,
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=delin,
                axis="column",
                )
            """

        if do_appendix_pcs==True:
            print("##########################")
            print("# create do_appendix_pcs #")
            print("##########################")

            combine_two_png(
                self.outpng_pca_hexmap.replace("???","3"),
                self.outpng_pca_hexmap.replace("???","4"),
                self.appendix_pca_mom0+"_tmp1.png",
                self.box_map,
                self.box_map,
                delin=delin,
                )
            combine_two_png(
                self.appendix_pca_mom0+"_tmp1.png",
                self.outpng_pca_hexmap.replace("???","5"),
                self.appendix_pca_mom0,
                "100000x100000+0+0",
                self.box_map,
                delin=delin,
                )

    ########################
    # immagick_figures_sub #
    ########################

    def immagick_figures_sub(
        self,
        delin                     = False,
        do_final_pca1_mom0_podium = False,
        do_final_hex_radial       = False,
        do_final_pca_r13co        = False,
        ):
        """
        """

        if do_final_pca1_mom0_podium==True:
            print("#################################")
            print("# create final_pca1_mom0_podium #")
            print("#################################")

            # pca1 mom0
            combine_two_png(
                self.outpng_pca1_mom0_1st,
                self.outpng_pca1_mom0_2nd,
                self.final_pca_mom0_podium+"_tmp1.png",
                self.box_map_noylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_pca1_mom0_3rd,
                self.outpng_pca1_mom0_4th,
                self.final_pca_mom0_podium+"_tmp2.png",
                self.box_map_noxylabel,
                self.box_map_noxylabel,
                delin=delin,
                )
            combine_two_png(
                self.final_pca_mom0_podium+"_tmp1.png",
                self.final_pca_mom0_podium+"_tmp2.png",
                self.final_pca_mom0_podium+"_pca1.png",
                "10000x10000+0+0",
                "10000x10000+0+0",
                delin=True,
                )

            # pca2 mom0
            combine_two_png(
                self.outpng_pca2_mom0_1st,
                self.outpng_pca2_mom0_2nd,
                self.final_pca_mom0_podium+"_tmp1.png",
                self.box_map,
                self.box_map_noxlabel,
                delin=delin,
                )
            combine_two_png(
                self.outpng_pca2_mom0_3rd,
                self.outpng_pca2_mom0_4th,
                self.final_pca_mom0_podium+"_tmp2.png",
                self.box_map_noxlabel,
                self.box_map_noxlabel,
                delin=delin,
                )
            combine_two_png(
                self.final_pca_mom0_podium+"_tmp1.png",
                self.final_pca_mom0_podium+"_tmp2.png",
                self.final_pca_mom0_podium+"_pca2.png",
                "100000x100000+0+0",
                "100000x100000+0+0",
                delin=True,
                )

            # combine
            combine_two_png(
                self.final_pca_mom0_podium+"_pca1.png",
                self.final_pca_mom0_podium+"_pca2.png",
                self.final_pca_mom0_podium,
                "100000x100000+0+0",
                "100000x100000+0+0",
                axis="column",
                delin=True,
                )

        if do_final_hex_radial==True:
            print("###########################")
            print("# create final_hex_radial #")
            print("###########################")

            combine_two_png(
                self.outpng_radial1,
                self.outpng_radial2,
                self.final_hex_radial+"_tmp1.png",
                self.box_map,
                self.box_map,
                delin=delin,
                )
            combine_two_png(
                self.final_hex_radial+"_tmp1.png",
                self.outpng_radial3,
                self.final_hex_radial,
                "100000x100000+0+0",
                self.box_map,
                axis="column",
                delin=delin,
                )
            os.system("rm -rf " + self.final_hex_radial + "_tmp1.png")

        if do_final_pca_r13co==True:
            print("##########################")
            print("# create final_pca_r13co #")
            print("##########################")

            combine_three_png(
                self.outpng_pca_hexmap_r13co.replace("???","1"),
                self.outpng_pca_hexmap_r13co.replace("???","2"),
                self.outpng_pca_scatter_r13co,
                self.final_pca_r13co,
                self.box_map,
                self.box_map,
                self.box_map,
                delin=delin,
                )

    #####################
    # plot_mol_richness #
    #####################

    def plot_mol_richness(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # extract mom0 data
        header,data_mom0,data_err,ra,dec,r = self._read_table(self.table_hex_obs)

        total_c = data_mom0[:,0] * 0
        for i in range(len(header)):
            this_c    = data_mom0[:,i]
            this_cerr = data_err[:,i]
            this_c    = np.where(this_c>=this_cerr*self.snr_mom,1,0)
            total_c   = total_c + this_c

        self._plot_hexmap(
            self.outpng_extra_richness,
            ra,
            dec,
            total_c,
            "Molecular richness",
            cmap      = "gnuplot",
            ann       = True,
            add_text  = False,
            lim       = 28,
            size      = 780,
            label     = "Number of lines",
            scalebar  = "500pc",
            textcolor = "white",
            )

    ########################
    # referee_meas_rms_snr #
    ########################

    def referee_meas_rms_snr(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # extract mom0 data
        header,data_mom0,data_emom0,x,y,r = self._read_table(self.table_hex_obs)

        for this_line in header:
            mom0         = np.array(data_mom0[:,np.where(header==this_line)].flatten())
            emom0        = np.array(data_emom0[:,np.where(header==this_line)].flatten())
            cut          = np.where((mom0!=0) & (emom0!=0) & (r<=self.r_sbr_as))
            mom0         = mom0[cut]
            emom0        = emom0[cut]
            snr          = mom0/emom0

            if len(mom0)>10:
                median_emom0 = np.median(emom0)
                p16_snr      = str(np.round(np.percentile(snr[snr>=self.snr_mom],16),1))
                median_snr   = str(np.round(np.median(snr[snr>=self.snr_mom]),1))
                p84_snr      = str(np.round(np.percentile(snr[snr>=self.snr_mom],84),1))
                peak_snr     = str(np.round(np.max(snr[snr>=self.snr_mom]),1))
                print(this_line, median_emom0, p16_snr+"-"+median_snr+"-"+p84_snr+"-"+peak_snr, len(mom0))

    #######################
    # plot_max_line_graph # Figure 5
    #######################

    def plot_max_line_graph(self,denom="co10",ylim=[-2.2,0.9]):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # start
        offset = 0 # 10
        angle1 = -15 - offset
        angle2 = -115 + offset
        angle3 = 165 - offset
        angle4 = 65 + offset

        # get table
        header,data_mom0,data_err,x,y,r = self._read_table(self.table_hex_obs)
        theta_deg = np.degrees(np.arctan2(x, y))
        header    = np.array([s for s in header if not "extinction" in s])

        # get line data
        list_name = []
        list_cnd  = []
        list_out  = []
        list_disk = []
        for this_name in header:
            # this_line
            line_index = np.where(header==this_name)
            data_line  = np.array(data_mom0[:,line_index].flatten())
            err_line   = np.array(data_err[:,line_index].flatten())
            data_line[np.isinf(data_line)] = 0
            data_line[np.isnan(data_line)] = 0
            data_line  = np.where((r<=self.r_sbr_as)&(data_line>=err_line*self.snr_mom),data_line,0)

            # 13co10
            tco_index  = np.where(header==denom)
            data_tco   = np.array(data_mom0[:,tco_index].flatten())
            err_tco    = np.array(data_err[:,tco_index].flatten())
            data_tco[np.isinf(data_tco)] = 0
            data_tco[np.isnan(data_tco)] = 0
            data_tco   = np.where((r<=self.r_sbr_as)&(data_line>=err_line*self.snr_mom),data_tco,0)

            if len(data_line[data_line>0])>=10:
                raduis    = self.r_cnd_as
                this_cnd  = np.where(r<raduis,data_line,0)
                tco_cnd   = np.where(r<raduis,data_tco,0)
                if this_name!="siiisii_ratio":
                    this_cnd  = this_cnd / tco_cnd

                this_no   = np.where((theta_deg>=angle1)&(theta_deg<angle4)&(r<self.r_sbr_as)&(r>=raduis),data_line,0)
                this_zo   = np.where((theta_deg>=angle3)&(r<self.r_sbr_as)&(r>=raduis),data_line,0)
                this_zo   = np.where((theta_deg<angle2)&(r<self.r_sbr_as)&(r>=raduis),data_line,this_zo)
                this_out  = np.array(this_no + this_zo)
                tco_no    = np.where((theta_deg>=angle1)&(theta_deg<angle4)&(r<self.r_sbr_as)&(r>=raduis),data_tco,0)
                tco_zo    = np.where((theta_deg>=angle3)&(r<self.r_sbr_as)&(r>=raduis),data_tco,0)
                tco_zo    = np.where((theta_deg<angle2)&(r<self.r_sbr_as)&(r>=raduis),data_tco,tco_zo)
                tco_out   = np.array(tco_no + tco_zo)
                if this_name!="siiisii_ratio":
                    this_out  = this_out / tco_out

                this_wd   = np.where((theta_deg<=angle1)&(theta_deg>angle2)&(r<self.r_sbr_as)&(r>=raduis),data_line,0)
                this_ed   = np.where((theta_deg<=angle3)&(theta_deg>angle4)&(r<self.r_sbr_as)&(r>=raduis),data_line,0)
                this_disk = np.array(this_wd + this_ed)
                tco_wd    = np.where((theta_deg<=angle1)&(theta_deg>angle2)&(r<self.r_sbr_as)&(r>=raduis),data_tco,0)
                tco_ed    = np.where((theta_deg<=angle3)&(theta_deg>angle4)&(r<self.r_sbr_as)&(r>=raduis),data_tco,0)
                tco_disk  = np.array(tco_wd + tco_ed)
                if this_name!="siiisii_ratio":
                    this_disk = this_disk / tco_disk

                if this_name!=denom:
                    list_name.append(this_name)
                    list_cnd.append(np.round(np.nanmax(this_cnd), 3))
                    list_out.append(np.round(np.nanmax(this_out), 3))
                    list_disk.append(np.round(np.nanmax(this_disk), 3))

        # summalize
        list_output = np.c_[list_name, list_cnd, list_out, list_disk]
        list_output_sort = list_output[ np.argsort(list_output[:,2].astype("float32")/list_output[:,3].astype("float32")) ]
        siiisii_ratio    = np.array([s for s in list_output_sort if "siiisii_ratio" in s[0]][0])
        list_output_sort = np.array([s for s in list_output_sort if not "siiisii_ratio" in s[0]])

        # plot
        y_cnd  = np.log10(list_output_sort[:,1].astype("float32"))
        y_out  = np.log10(list_output_sort[:,2].astype("float32"))
        y_disk = np.log10(list_output_sort[:,3].astype("float32"))
        x = []
        for this_name in list_output_sort[:,0]:
            this_name = this_name.replace("1110","(11-10)")
            this_name = this_name.replace("1211","(12-11)")
            this_name = this_name.replace("10","(1-0)")
            this_name = this_name.replace("21","(2-1)")
            this_name = this_name.replace("(1-0)9","(10-9)")
            this_name = this_name.replace("12","$^{12}$")
            this_name = this_name.replace("13","$^{13}$")
            this_name = this_name.replace("18","$^{18}$")
            this_name = this_name.replace("c3","c$_3$").replace("h3","H$_3$")
            this_name = this_name.replace("ci","[CI]").replace("n2","n$_2$")
            this_name = this_name.replace("c","C").replace("o","O")
            this_name = this_name.replace("n","N").replace("h","H")
            this_name = this_name.replace("p","$^+$").replace("s","S")
            this_name = this_name.replace("SiiiSii_ratiO","[SIII]/[SII] ratio")
            this_name = this_name.replace("(1-0)H","(1-0)h")
            this_name = this_name.replace("11-(1-0)","11-10")
            this_name = this_name.replace("($^{12}$-11)","(12-11)")
            this_name = this_name.replace("(1-0)l","(1$_{1/2}$-0$_{1/2}$)")
            this_name = this_name.replace("(1-0)h","(1$_{3/2}$-0$_{1/2}$)")
            this_name = this_name.replace("CH$_3$OH(2-1)","CH$_3$OH(2$_K$-1$_K$)")
            x.append(this_name)

        # set plt, ax
        fig  = plt.figure(figsize=(13,7))
        plt.rcParams["font.size"] = 16
        gs   = gridspec.GridSpec(nrows=11, ncols=11)
        ax   = plt.subplot(gs[0:10,0:9])
        ax2  = plt.subplot(gs[0:10,9:10])
        ax2b = ax2.twinx()

        # set ax parameter
        myax_set(
        ax,
        grid=None,
        xlim=[-0.5,15.5],
        ylim=ylim,
        xlabel=None,
        ylabel="log ratio relative to $^{12}$CO(1-0)",
        adjust=[0.1,0.963,0.25,0.93],
        )
        myax_set(
        ax2,
        grid=None,
        xlim=[15.5,16.5],
        ylim=ylim,
        xlabel=None,
        ylabel=None,
        adjust=[0.1,0.963,0.25,0.93],
        )
        myax_set(
        ax2b,
        grid=None,
        xlim=[15.5,16.5],
        ylim=ylim,
        xlabel=None,
        ylabel="log [SIII]/[SII] ratio",
        adjust=[0.1,0.963,0.25,0.93],
        )
        ax2.tick_params(labelleft=False,labelright=True)
        ax2b.tick_params(labelleft=False,labelright=True)

        markersize = 15
        ax.plot(range(len(x)),y_disk,c="grey",lw=2,marker="s",markersize=markersize,markeredgewidth=0)
        ax.plot(range(len(x)),y_cnd,c="tomato",lw=2,marker="s",markersize=markersize,markeredgewidth=0)
        ax.plot(range(len(x)),y_out,c="deepskyblue",lw=2,marker="s",markersize=markersize,markeredgewidth=0)
        ax2b.plot(len(x),np.log10(float(siiisii_ratio[3])),c="grey",lw=2,marker="o",markersize=markersize,markeredgewidth=0)
        ax2b.plot(len(x),np.log10(float(siiisii_ratio[1])),c="tomato",lw=2,marker="o",markersize=markersize,markeredgewidth=0)
        ax2b.plot(len(x),np.log10(float(siiisii_ratio[2])),c="deepskyblue",lw=2,marker="o",markersize=markersize,markeredgewidth=0)

        # x axis
        ax.set_xticks(range(len(x)))
        ax.set_xticklabels(x, rotation = 60, ha="right")
        ax2.set_xticks([16.0])
        ax2.set_xticklabels(["[SIII]/[SII] ratio"], rotation = 60, ha="right")

        # text
        ax.text(0.015, 0.91, "Outflow", color="deepskyblue", transform=ax.transAxes, weight="bold", fontsize=22)
        ax.text(0.015, 0.85, "CND", color="tomato", transform=ax.transAxes, weight="bold", fontsize=22)
        ax.text(0.015, 0.79, "Non-outflow", color="grey", transform=ax.transAxes, weight="bold", fontsize=22)

        # ann
        ax.plot([8.5,8.5],[-2.4,2.4],"--",c="black",lw=2)
        ax.text(12.0, -1.5, "Lines enhanced", color="black", fontsize=18, ha="center", style="italic")
        ax.text(12.0, -1.69, "in the outflow", color="black", fontsize=18, ha="center", style="italic")

        ax.plot([3.5,3.5],[-2.4,2.4],"--",c="black",lw=2)
        ax.text(1.5, 0.05, "Lines suppressed", color="black", fontsize=18, ha="center", style="italic")
        ax.text(1.5, -0.14, "in the outflow", color="black", fontsize=18, ha="center", style="italic")

        # save
        os.system("rm -rf " + self.outpng_line_graph.replace(".png","_"+denom+".png"))
        plt.savefig(self.outpng_line_graph.replace(".png","_"+denom+".png"), dpi=300)

    ################################
    # plot_hexmap_pca_ratio_podium # Figure 4
    ################################

    def plot_hexmap_pca_ratio_podium(self,denom1="co10",denom2="co10"):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)
        factor = 1.0

        pc1_name1  = "h13cn10"
        pc1_name2  = "hc3n109"
        pc1_name3  = "hcn10"
        pc1_name4  = "hcop10"

        pc2_name1  = "cn10h"
        pc2_name2  = "cch10"
        pc2_name3  = "hnc10"
        pc2_name4  = "cn10l"

        # extract mom0 data
        header,data_mom0,_,x,y,r = self._read_table(self.table_hex_obs)

        denom1_name  = denom1
        denom1_index = np.where(header==denom1_name)
        denom1_z     = np.array(data_mom0[:,denom1_index].flatten())

        denom2_name  = denom2
        denom2_index = np.where(header==denom2_name)
        denom2_z     = np.array(data_mom0[:,denom2_index].flatten())

        # get PC1 podium
        pc1_index1 = np.where(header==pc1_name1)
        pc1_index2 = np.where(header==pc1_name2)
        pc1_index3 = np.where(header==pc1_name3)
        pc1_index4 = np.where(header==pc1_name4)

        pc1_z1     = np.array(data_mom0[:,pc1_index1].flatten()) / denom1_z
        pc1_z2     = np.array(data_mom0[:,pc1_index2].flatten()) / denom1_z
        pc1_z3     = np.array(data_mom0[:,pc1_index3].flatten()) / denom1_z
        pc1_z4     = np.array(data_mom0[:,pc1_index4].flatten()) / denom1_z

        pc1_z1[np.isinf(pc1_z1)] = 0
        pc1_z2[np.isinf(pc1_z2)] = 0
        pc1_z3[np.isinf(pc1_z3)] = 0
        pc1_z4[np.isinf(pc1_z4)] = 0
        pc1_z1[np.isnan(pc1_z1)] = 0
        pc1_z2[np.isnan(pc1_z2)] = 0
        pc1_z3[np.isnan(pc1_z3)] = 0
        pc1_z4[np.isnan(pc1_z4)] = 0

        pc1_z1     = np.where(r<=self.r_sbr_as,pc1_z1,0)
        pc1_z2     = np.where(r<=self.r_sbr_as,pc1_z2,0)
        pc1_z3     = np.where(r<=self.r_sbr_as,pc1_z3,0)
        pc1_z4     = np.where(r<=self.r_sbr_as,pc1_z4,0)

        pc1_z1     = np.where(pc1_z1>=np.max(pc1_z1)/factor, np.max(pc1_z1)/factor, pc1_z1)
        pc1_z2     = np.where(pc1_z2>=np.max(pc1_z2)/factor, np.max(pc1_z2)/factor, pc1_z2)
        pc1_z3     = np.where(pc1_z3>=np.max(pc1_z3)/factor, np.max(pc1_z3)/factor, pc1_z3)
        pc1_z4     = np.where(pc1_z4>=np.max(pc1_z4)/factor, np.max(pc1_z4)/factor, pc1_z4)

        pc1_z1_sort = pc1_z1.flatten()
        pc1_z2_sort = pc1_z2.flatten()
        pc1_z3_sort = pc1_z3.flatten()
        pc1_z4_sort = pc1_z4.flatten()
        pc1_z1_sort.sort()
        pc1_z2_sort.sort()
        pc1_z3_sort.sort()
        pc1_z4_sort.sort()
        pc1_z1     = np.where(pc1_z1==np.max(pc1_z1), pc1_z1_sort[-2], pc1_z1)
        pc1_z2     = np.where(pc1_z2==np.max(pc1_z2), pc1_z2_sort[-2], pc1_z2)
        pc1_z3     = np.where(pc1_z3==np.max(pc1_z3), pc1_z3_sort[-2], pc1_z3)
        pc1_z4     = np.where(pc1_z4==np.max(pc1_z4), pc1_z4_sort[-2], pc1_z4)

        # get PC2 podium
        pc2_index1 = np.where(header==pc2_name1)
        pc2_index2 = np.where(header==pc2_name2)
        pc2_index3 = np.where(header==pc2_name3)
        pc2_index4 = np.where(header==pc2_name4)

        pc2_z1     = np.array(data_mom0[:,pc2_index1].flatten()) / denom2_z
        pc2_z2     = np.array(data_mom0[:,pc2_index2].flatten()) / denom2_z
        pc2_z3     = np.array(data_mom0[:,pc2_index3].flatten()) / denom2_z
        pc2_z4     = np.array(data_mom0[:,pc2_index4].flatten()) / denom2_z

        pc2_z1[np.isinf(pc2_z1)] = 0
        pc2_z2[np.isinf(pc2_z2)] = 0
        pc2_z3[np.isinf(pc2_z3)] = 0
        pc2_z4[np.isinf(pc2_z4)] = 0
        pc2_z1[np.isnan(pc2_z1)] = 0
        pc2_z2[np.isnan(pc2_z2)] = 0
        pc2_z3[np.isnan(pc2_z3)] = 0
        pc2_z4[np.isnan(pc2_z4)] = 0

        pc2_z1     = np.where(r<=self.r_sbr_as,pc2_z1,0)
        pc2_z2     = np.where(r<=self.r_sbr_as,pc2_z2,0)
        pc2_z3     = np.where(r<=self.r_sbr_as,pc2_z3,0)
        pc2_z4     = np.where(r<=self.r_sbr_as,pc2_z4,0)

        pc2_z1     = np.where(pc2_z1>=np.max(pc2_z1)/factor, np.max(pc2_z1)/factor, pc2_z1)
        pc2_z2     = np.where(pc2_z2>=np.max(pc2_z2)/factor, np.max(pc2_z2)/factor, pc2_z2)
        pc2_z3     = np.where(pc2_z3>=np.max(pc2_z3)/factor, np.max(pc2_z3)/factor, pc2_z3)
        pc2_z4     = np.where(pc2_z4>=np.max(pc2_z4)/factor, np.max(pc2_z4)/factor, pc2_z4)

        pc2_z1_sort = pc2_z1.flatten()
        pc2_z2_sort = pc2_z2.flatten()
        pc2_z3_sort = pc2_z3.flatten()
        pc2_z4_sort = pc2_z4.flatten()
        pc2_z1_sort.sort()
        pc2_z2_sort.sort()
        pc2_z3_sort.sort()
        pc2_z4_sort.sort()
        pc2_z1     = np.where(pc2_z1==np.max(pc2_z1), pc2_z1_sort[-2], pc2_z1)
        pc2_z2     = np.where(pc2_z2==np.max(pc2_z2), pc2_z2_sort[-2], pc2_z2)
        pc2_z3     = np.where(pc2_z3==np.max(pc2_z3), pc2_z3_sort[-2], pc2_z3)
        pc2_z4     = np.where(pc2_z4==np.max(pc2_z4), pc2_z4_sort[-2], pc2_z4)

        if denom1_name=="hcn10":
            denom1_str="HCN(1-0)"
        if denom1_name=="13co10":
            denom1_str="$^{13}$CO(1-0)"
        if denom1_name=="c18o10":
            denom1_str="C$^{18}$O(1-0)"
        if denom1_name=="co10":
            denom1_str="CO(1-0)"

        if denom2_name=="hcn10":
            denom2_str="HCN(1-0)"
        if denom2_name=="13co10":
            denom2_str="$^{13}$CO(1-0)"
        if denom2_name=="c18o10":
            denom2_str="C$^{18}$O(1-0)"
        if denom2_name=="co10":
            denom2_str="CO(1-0)"

        # PC1 podium+1
        self._plot_hexmap(
            self.outpng_pca1_ratio_1st,
            x,
            y,
            pc1_z1,
            "H$^{13}$CN(1-0)/"+denom1_str+" (highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            )

        self._plot_hexmap(
            self.outpng_pca1_ratio_2nd,
            x,
            y,
            pc1_z2,
            "HC$_3$N(10-9)/"+denom1_str+" (2nd highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            )

        self._plot_hexmap(
            self.outpng_pca1_ratio_3rd,
            x,
            y,
            pc1_z3,
            "HCN(1-0)/"+denom1_str+" (3rd highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            )

        self._plot_hexmap(
            self.outpng_pca1_ratio_4th,
            x,
            y,
            pc1_z4,
            "HCO$^+$(1-0)/"+denom1_str+" (4th highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            )

        # PC2 podium+1
        self._plot_hexmap(
            self.outpng_pca2_ratio_1st,
            x,
            y,
            pc2_z1,
            "CN(1$_{3/2}$-0$_{1/2}$)/"+denom2_str+" (highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="",
            )

        self._plot_hexmap(
            self.outpng_pca2_ratio_2nd,
            x,
            y,
            pc2_z2,
            "CCH(1-0)/"+denom2_str+" (2nd highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="",
            )

        self._plot_hexmap(
            self.outpng_pca2_ratio_3rd,
            x,
            y,
            pc2_z3,
            "HNC(1-0)/"+denom2_str+" (3rd highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="",
            )

        self._plot_hexmap(
            self.outpng_pca2_ratio_4th,
            x,
            y,
            pc2_z4,
            "CN(1$_{1/2}$-0$_{1/2}$)/"+denom2_str+" (4th highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="",
            )

    ###################
    # plot_hexmap_pca # Figure 3
    ###################

    def plot_hexmap_pca(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_pca_mom0,taskname)

        # extract mom0 data
        data = np.loadtxt(self.table_hex_pca_mom0)
        x        = data[:,0]
        y        = data[:,1]
        r        = np.sqrt(x**2 + y**2)
        data_pca = data[:,2:]

        ###################
        # plot PC scatter #
        ###################
        print("# plot " + self.outpng_pca_scatter)

        table_hex_pca_mom0_score = self.table_hex_pca_mom0.replace(".txt","_score.txt")
        data_score = np.loadtxt(table_hex_pca_mom0_score,dtype="str")
        score_name = data_score[:,0]
        score_pc1  = data_score[:,1].astype(np.float64)
        score_pc2  = data_score[:,2].astype(np.float64)
        score_pc1  = score_pc1 / np.std(score_pc1)
        score_pc2  = score_pc2 / np.std(score_pc2) * -1

        # set plt, ax
        fig = plt.figure(figsize=(13,10))
        plt.rcParams["font.size"] = 16
        gs = gridspec.GridSpec(nrows=10, ncols=10)
        ax = plt.subplot(gs[0:10,0:10])

        # set ax parameter
        myax_set(
        ax,
        grid=None,
        xlim=[-3.2,1.8],
        ylim=[-1.6,3.4],
        xlabel="PC1",
        ylabel="PC2",
        adjust=[0.023,0.963,0.10,0.93],
        )
        ax.set_aspect('equal', adjustable='box')

        for i in range(len(score_name)):
            pc1 = score_pc1[i]
            pc2 = score_pc2[i]
            ax.plot([0,pc1],[0,pc2],"-",color="grey",lw=2)

            if score_name[i]=="n2hp10":
                ax.text(pc1,pc2,"N$_2$H$^+$",fontsize=18,ha="center",va="top")
            elif score_name[i]=="hc3n109":
                continue
            elif score_name[i]=="hc3n1110":
                continue
            elif score_name[i]=="hc3n1211":
                ax.text(pc1,pc2-0.15,"HC$_3$Nx3",fontsize=18,ha="left",va="center")
            elif score_name[i]=="h13cn10":
                ax.text(pc1,pc2-0.1,"H$^{13}$CN",fontsize=18,ha="left",va="bottom")
            elif score_name[i]=="cs21":
                ax.text(pc1,pc2,"CS",fontsize=18,ha="center",va="top")
            elif score_name[i]=="hcn10":
                ax.text(pc1,pc2,"HCN",fontsize=18,ha="left",va="center")
            elif score_name[i]=="hcop10":
                ax.text(pc1,pc2,"HCO$^+$",fontsize=18,ha="left",va="center")
            elif score_name[i]=="cn10l":
                ax.text(pc1,pc2,"CN(1-0)l",fontsize=18,ha="left",va="center")
            elif score_name[i]=="hnc10":
                ax.text(pc1,pc2,"HNC",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="cn10h":
                ax.text(pc1,pc2,"CN(1-0)h",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="ci10":
                ax.text(pc1,pc2,"[CI]",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="cch10":
                ax.text(pc1,pc2,"CCH",fontsize=18,ha="right",va="bottom")
            elif score_name[i]=="siiisii_ratio":
                ax.text(pc1,pc2,"[SIII]/[SII] ratio",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="co10":
                ax.text(pc1,pc2,"CO",fontsize=18,ha="right",va="center")
            elif score_name[i]=="13co10":
                ax.text(pc1,pc2,"$^{13}$CO",fontsize=18,ha="right",va="center")
            elif score_name[i]=="c18o10":
                ax.text(pc1,pc2,"C$^{18}$O",fontsize=18,ha="right",va="center")
            elif score_name[i]=="ch3oh21":
                ax.text(pc1,pc2,"CH$_3$OH",fontsize=18,ha="center",va="top")
            else:
                ax.text(pc1,pc2,score_name[i],fontsize=14)

        ax.text(0.03, 0.93, "(a) PC1 vs. PC2", color="black", transform=ax.transAxes, weight="bold", fontsize=24)

        # save
        os.system("rm -rf " + self.outpng_pca_scatter)
        plt.savefig(self.outpng_pca_scatter, dpi=300)

        #################
        # plot PCA maps #
        #################
        anntexts = [True,False,False,False,False]
        cmaps    = ["Reds","PuBu","PuBu","PuBu","PuBu"]
        headers  = ["b","c","a","b","c"]
        for i in range(len(data_pca[0])):
            this_c    = data_pca[:,i]
            this_x    = x[this_c!=0]
            this_y    = y[this_c!=0]
            this_c    = this_c[this_c!=0]
            this_text = anntexts[i]
            thid_cmap = cmaps[i]

            if abs(np.min(this_c))>abs(np.max(this_c)):
                this_c = this_c * -1

            this_c = np.where(this_c>np.max(this_c)/1.5,np.max(this_c)/1.5,this_c)

            output = self.outpng_pca_hexmap.replace("???",str(i+1))

            print("# plot " + output)
            self._plot_hexmap(
                output,
                this_x,
                this_y,
                this_c,
                "(" + headers[i] + ") PC"+str(i+1),
                cmap=thid_cmap,
                ann=True,
                add_text=this_text,
                lim=13,
                size=3600,
                )

    ################
    # plot_envmask # Figures 1b
    ################

    def plot_envmask(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # start
        offset = 0 # 10
        angle1 = -15 - offset
        angle2 = -115 + offset
        angle3 = 165 - offset
        angle4 = 65 + offset

        # extract line name
        _,_,_,ra,dec,r = self._read_table(self.table_hex_obs)
        theta_deg = np.degrees(np.arctan2(ra, dec))

        #
        mask = np.where(r<self.r_sbr_as,1,0)
        mask = np.where((theta_deg>=angle1)&(theta_deg<angle4)&(r<self.r_sbr_as)&(r>=self.r_cnd_as),2,mask)
        mask = np.where((theta_deg>=angle3)&(r<self.r_sbr_as)&(r>=self.r_cnd_as),2,mask)
        mask = np.where((theta_deg<angle2)&(r<self.r_sbr_as)&(r>=self.r_cnd_as),2,mask)
        mask = np.where(r<self.r_cnd_as,3,mask)

        os.system("rm -rf " + self.outpng_envmask)
        self._plot_hexmap(
            self.outpng_envmask,
            ra,
            dec,
            mask,
            "(b) Region definition",
            #cmap      = "gist_rainbow",
            ann       = True,
            add_text  ="env",
            lim       = 13,
            size      = 3600,
            label     = None,
            plot_cbar = False,
            )

    ####################
    # plot_hexmap_mom0 # Figures 1a and 2
    ####################

    def plot_hexmap_mom0(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # extract line name
        header,data_mom0,data_err,ra,dec,r = self._read_table(self.table_hex_obs)

        # plot
        for i in range(len(header)):
            this_c    = data_mom0[:,i]
            this_cerr = data_err[:,i]
            this_name = header[i]

            cut = np.where(r<=self.r_sbr_as)
            this_x    = ra[cut]
            this_y    = dec[cut]
            this_c    = this_c[cut]
            this_cerr = this_cerr[cut]
            this_c    = np.where(this_c>=this_cerr*self.snr_mom,this_c,0)

            output = self.outpng_mom0.replace("???",this_name)

            if this_name=="co10":
                co10 = data_mom0[:,i]
                print("# plot overall " + self.outpng_12co10_oveall)
                self._plot_hexmap(
                    self.outpng_12co10_oveall,
                    ra,
                    dec,
                    co10,
                    "(a) $^{12}$CO(1-0)",
                    ann       = True,
                    add_text  = False,
                    lim       = 28,
                    size      = 780,
                    label     = "(K km s$^{-1}$)",
                    scalebar  = "500pc",
                    textcolor = "white",
                    )

            if len(this_c[this_c!=0])>=10:
                this_name = this_name.replace("1110","(11-10)")
                this_name = this_name.replace("1211","(12-11)")
                this_name = this_name.replace("10","(1-0)")
                this_name = this_name.replace("21","(2-1)")
                this_name = this_name.replace("(1-0)9","(10-9)")
                this_name = this_name.replace("12","$^{12}$")
                this_name = this_name.replace("13","$^{13}$")
                this_name = this_name.replace("18","$^{18}$")
                this_name = this_name.replace("c3","c$_3$").replace("h3","H$_3$")
                this_name = this_name.replace("ci","[CI]").replace("n2","n$_2$")
                this_name = this_name.replace("c","C").replace("o","O")
                this_name = this_name.replace("n","N").replace("h","H")
                this_name = this_name.replace("p","$^+$").replace("s","S")
                this_name = this_name.replace("SiiiSii_ratiO","[SIII]/[SII] ratio")
                this_name = this_name.replace("(1-0)H","(1-0)h")
                this_name = this_name.replace("11-(1-0)","11-10")
                this_name = this_name.replace("($^{12}$-11)","(12-11)")
                this_name = this_name.replace("(1-0)l","(1$_{1/2}$-0$_{1/2}$)")
                this_name = this_name.replace("(1-0)h","(1$_{3/2}$-0$_{1/2}$)")
                this_name = this_name.replace("CH$_3$OH(2-1)","CH$_3$OH(2$_K$-1$_K$)")

                # plot
                if this_name=="[SIII]/[SII] ratio":
                    label = "Ratio"
                else:
                    label = "(K km s$^{-1}$)"

                print("# plot " + output + " " + this_name)
                self._plot_hexmap(
                    output,
                    this_x,
                    this_y,
                    this_c,
                    this_name,# + " [$N_{pixel}$ = " + str(len(this_c[this_c!=0])) + "]",
                    ann      = True,
                    add_text = False,
                    lim      = 13,
                    size     = 3600,
                    label    = label,
                    )

    ###############
    # run_hex_pca #
    ###############

    def run_hex_pca(
        self,
        output,
        outtxt,
        denom=None,
        reverse=False,
        ):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # extract line name
        list_name,array_data,array_err,x,y,r = self._read_table(self.table_hex_obs)

        # main
        data, data_name = [], []
        for i in range(len(list_name)):
            this_flux = array_data[:,i]
            this_err  = array_err[:,i]
            this_name = list_name[i]

            if this_name==denom:
                continue

            if denom!=None:
                index      = np.where(list_name==denom)[0][0]
                data_denom = array_data[:,index]
                err_denom  = array_err[:,index]
            else:
                data_denom = None
                err_denom  = None

            # sn cut and zero padding
            this_flux = self._process_hex_for_pca(this_flux,this_err,r,data_denom,err_denom)

            # limiting by #data
            len_data = len(this_flux[this_flux>0])
            if len_data>=10:
                print("# meet " + this_name + " #=" + str(len_data))
                data.append(this_flux.flatten())
                data_name.append(this_name)
            else:
                print("# skip " + this_name + " #=" + str(len_data))

        # run
        os.system("rm -rf " + output)
        array_hex_pca, pca_score = pca_2d_hex(
            x,
            y,
            data,
            data_name,
            output,
            "_150pc",
            self.snr_mom,
            self.beam,
            self.gridsize,
            reverse=reverse,
            factor=2,
            )

        header = "ra(deg) dec(deg) PC1 PC2 ..."
        np.savetxt(outtxt,array_hex_pca,header=header)

        header = "line PC1 PC2 ..."
        np.savetxt(outtxt.replace(".txt","_score.txt"),pca_score,header=header,fmt="%s")

    ################
    # hex_sampling #
    ################

    def hex_sampling(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name

        # sampling mom0
        maps_mom0 = glob.glob(self.outfits_mom0.replace("???","*"))
        maps_mom0 = [s for s in maps_mom0 if "err" not in s]
        maps_mom0.sort()
        maps_mom0.append(self.map_av)
        maps_mom0.append(self.map_ionization)

        check_first(maps_mom0[0],taskname)

        header = ["ra(deg)","dec(deg)"]
        for i in range(len(maps_mom0)):
            this_mom0 = maps_mom0[i]
            this_line = this_mom0.split("/")[-1].split("n1068_")[1].split(".fits")[0]
            print("# sampling " + this_mom0.split("/")[-1])
            x,y,z = hexbin_sampling(
                this_mom0,
                self.ra_agn,
                self.dec_agn,
                beam=self.beam,
                gridsize=self.gridsize,
                err=False,
                )

            if i==0:
                output_hex = np.c_[x,y]

            output_hex = np.c_[output_hex,z]
            header.append(this_line)

        # sampling emom0
        maps_emom0 = glob.glob(self.outfits_emom0.replace("???","*"))
        maps_emom0.sort()
        maps_emom0.append(self.map_av)
        maps_emom0.append(self.map_ionization)

        for i in range(len(maps_emom0)):
            this_emom0 = maps_emom0[i]
            this_line  = this_emom0.split("/")[-1].split("n1068_")[1].split(".fits")[0]
            print("# sampling " + this_emom0.split("/")[-1])
            x,y,z = hexbin_sampling(
                this_emom0,
                self.ra_agn,
                self.dec_agn,
                beam=self.beam,
                gridsize=self.gridsize,
                err=True,
                )

            if this_line=="extinction":
                z = z * 0
            elif this_line=="siiisii_ratio":
                z = z * 0

            output_hex = np.c_[output_hex,z]
            header.append(this_line+"(err)")

        header = " ".join(header)
        np.savetxt(self.table_hex_obs,output_hex,header=header)

    ##############
    # align_maps #
    ##############

    def align_maps(self):
        """
        """

        template = "template.image"
        run_importfits(self.map_av,template)

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(template,taskname)

        # regrid mom0
        for this_map in self.maps_mom0:
            this_output  = self.outmap_mom0.replace("???",this_map.split("/")[-1].split("_")[3])
            this_outfits = self.outfits_mom0.replace("???",this_map.split("/")[-1].split("_")[3])
            run_imregrid(this_map, template, this_output)
            run_exportfits(this_output, this_outfits, True, True, True)

        # regrid emom0
        for this_map in self.maps_emom0:
            this_output  = self.outmap_emom0.replace("???",this_map.split("/")[-1].split("_")[3])
            this_outfits = self.outfits_emom0.replace("???",this_map.split("/")[-1].split("_")[3])
            run_imregrid(this_map, template, this_output)
            run_exportfits(this_output, this_outfits, True, True, True)

        # cleanup
        os.system("rm -rf template.image")

    ########################
    # _process_hex_for_pca #
    ########################

    def _process_hex_for_pca(
        self,
        this_flux,
        this_err,
        this_r,
        denom_flux=None,
        denom_err=None,
        ):
        """
        """

        # sn cut
        this_thres = abs(this_err * self.snr_mom)
        this_flux  = np.where(this_flux>=this_thres, this_flux, 0)

        if denom_flux!=None:
            denom_flux = np.where(denom_flux>=denom_err*self.snr_mom, denom_flux, 0)
            this_flux  = this_flux / denom_flux
            this_flux[np.isinf(this_flux)] = 0
            this_flux[np.isnan(this_flux)] = 0

        # normalize
        this_flux  = ( this_flux - np.mean(this_flux) ) / np.std(this_flux)

        # zero padding
        this_flux[np.isnan(this_flux)] = 0
        this_flux[np.isinf(this_flux)] = 0

        # extract center by masking
        this_flux = np.where(this_r<=self.r_sbr_as, this_flux, 0)
        this_err  = np.where(this_r<=self.r_sbr_as, this_err, 0)

        return this_flux

    ###############
    # _read_table #
    ###############

    def _read_table(self,txtdata):
        """
        """

        # extract line name
        f = open(txtdata)
        header = f.readline()
        header = header.split(" ")[1:]
        header = [s.split("\n")[0] for s in header]
        f.close()

        # extract mom0 data
        data = np.loadtxt(txtdata)
        x          = data[:,0]
        y          = data[:,1]
        r          = np.sqrt(x**2 + y**2)
        len_data   = (len(data[0])-2)/2

        array_data = data[:,2:len_data+2]
        array_err  = data[:,len_data+2:]
        list_name  = np.array(header[2:len_data+2])

        return list_name, array_data, array_err, x, y, r

    ################
    # _plot_hexmap #
    ################

    def _plot_hexmap(
        self,
        outpng,
        x,y,c,
        title,
        title_cbar="(K km s$^{-1}$)",
        cmap="rainbow",
        plot_cbar=True,
        ann=False,
        lim=29.5,
        size=690,
        add_text=False,
        label="",
        bgcolor="white",
        scalebar="100pc",
        textcolor="black",
        ):
        """
        """

        # set plt, ax
        fig = plt.figure(figsize=(13,10))
        gs = gridspec.GridSpec(nrows=10, ncols=10)
        ax = plt.subplot(gs[0:10,0:10])
        fig.patch.set_facecolor(bgcolor)

        # set ax parameter
        myax_set(
        ax,
        grid=None,
        xlim=[lim, -lim],
        ylim=[-lim, lim],
        xlabel="R.A. offset (arcsec)",
        ylabel="Decl. offset (arcsec)",
        adjust=[0.10,0.99,0.10,0.93],
        fsize=25,
        )
        ax.set_aspect('equal', adjustable='box')

        # plot
        if add_text!="env":
            im = ax.scatter(x, y, s=size, c=c, cmap=cmap, marker="h", linewidths=0)#, vmin=0)
        else:
            ax.scatter(x[c==3], y[c==3], s=size, c="tomato", marker="h", linewidths=0)
            ax.scatter(x[c==2], y[c==2], s=size, c="deepskyblue", marker="h", linewidths=0)
            ax.scatter(x[c==1], y[c==1], s=size, c="grey", marker="h", linewidths=0)
            im = ax.scatter(np.array(x)*1000, np.array(y)*1000, s=0, c=c, cmap=cmap, marker="h", linewidths=0, vmin=0)

        # cbar
        cbar = plt.colorbar(im)
        if plot_cbar==True:
            cax = fig.add_axes([0.19, 0.12, 0.025, 0.35])
            cb  = fig.colorbar(im, cax=cax)
            cb.set_label(label, color=textcolor)
            cb.ax.yaxis.set_tick_params(color=textcolor)
            cb.outline.set_color(textcolor)
            plt.setp(plt.getp(cb.ax.axes, 'yticklabels'), color=textcolor)

        # scale bar
        if scalebar=="100pc":
            bar = 100 / self.scale_pc
            ax.plot([-10,-10+bar],[-10,-10],"-",color=textcolor,lw=4)
            ax.text(-10, -10.5, "100 pc", color=textcolor,
                    horizontalalignment="right", verticalalignment="top")
        elif scalebar=="500pc":
            bar = 500 / self.scale_pc
            ax.plot([-22,-22+bar],[-22,-22],"-",color=textcolor,lw=4)
            ax.text(-22, -22.5, "500 pc", color=textcolor,
                    horizontalalignment="right", verticalalignment="top")

        # text
        ax.text(0.03, 0.93, title, color=textcolor, transform=ax.transAxes, weight="bold", fontsize=32)

        # ann
        if ann==True:
            theta1      = -10.0 # degree
            theta2      = 70.0 # degree
            fov_diamter = 16.5 # arcsec (12m+7m Band 8)

            fov_diamter = 16.5
            efov1 = patches.Ellipse(xy=(-0,0), width=fov_diamter,
                height=fov_diamter, angle=0, fill=False, edgecolor="black",
                alpha=1.0, lw=3.5)

            ax.add_patch(efov1)

            # plot NGC 1068 AGN and outflow geometry
            x1 = fov_diamter/2.0 * np.cos(np.radians(-1*theta1+90))
            y1 = fov_diamter/2.0 * np.sin(np.radians(-1*theta1+90))
            ax.plot([x1, -x1], [y1, -y1], "--", c="black", lw=3.5)
            x2 = fov_diamter/2.0 * np.cos(np.radians(-1*theta2+90))
            y2 = fov_diamter/2.0 * np.sin(np.radians(-1*theta2+90))
            ax.plot([x2, -x2], [y2, -y2], "--", c="black", lw=3.5)

        # add annotation comment
        if add_text==True:
            ax.plot([0,-7], [0,10], lw=3, c="black")
            ax.text(-10.5, 10.5, "AGN position", ha="right", va="center", weight="bold")
        elif add_text=="env":
            ax.text(12, -10, "CND", ha="left", va="center", color="tomato", weight="bold")
            ax.text(12, -11, "Outflow", ha="left", va="center", color="deepskyblue", weight="bold")
            ax.text(12, -12, "Non-outflow", ha="left", va="center", color="grey", weight="bold")

        # save
        os.system("rm -rf " + outpng)
        plt.savefig(outpng, dpi=300)

    ###############
    # _create_dir #
    ###############

    def _create_dir(self, this_dir):

        if self.refresh==True:
            print("## refresh " + this_dir)
            os.system("rm -rf " + this_dir)

        if not glob.glob(this_dir):
            print("## create " + this_dir)
            os.mkdir(this_dir)

        else:
            print("## not refresh " + this_dir)

    #############
    # _read_key #
    #############

    def _read_key(self, key, keyfile="fig", delimiter=",,,"):

        if keyfile=="gal":
            keyfile = self.keyfile_gal
        elif keyfile=="fig":
            keyfile = self.keyfile_fig

        keydata  = np.loadtxt(keyfile,dtype="str",delimiter=delimiter)
        keywords =\
             np.array([s.replace(" ","") for s in keydata[:,0]])
        values   = keydata[:,1]
        value    = values[np.where(keywords==key)[0][0]]

        return value

    ##########################
    # will be decommissioned #
    ##########################

    def plot_radial(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # get data
        data_cone_co10,r  = self._get_bicone_radial("co10")
        data_cone_hcn10,_ = self._get_bicone_radial("hcn10")
        data_cone_1st,_   = self._get_bicone_radial("cn10h")
        data_cone_2nd,_   = self._get_bicone_radial("hnc10")
        data_cone_3rd,_   = self._get_bicone_radial("cch10")

        data_disk_co10,_  = self._get_bicone_radial("co10",cone="out")
        data_disk_hcn10,_ = self._get_bicone_radial("hcn10",cone="out")
        data_disk_1st,_   = self._get_bicone_radial("cn10h",cone="out")
        data_disk_2nd,_   = self._get_bicone_radial("hnc10",cone="out")
        data_disk_3rd,_   = self._get_bicone_radial("cch10",cone="out")

        # plot
        xlim  = [2.1,9.6]

        rdata = [data_cone_3rd-data_cone_co10,data_disk_3rd-data_disk_co10]
        self._plot_radial(
            self.outpng_radial1,
            r,
            rdata,
            "(a) Radial CCH(1-0)/CO(1-0) ratio",
            size=1000/10,
            ylabel="log Ratio",
            xlim=xlim,
            ylim=[-2.3,0.1],
            ann=1,
            )

        rdata = [data_cone_1st-data_cone_hcn10,data_disk_1st-data_disk_hcn10]
        self._plot_radial(
            self.outpng_radial2,
            r,
            rdata,
            "(b) Radial CN(1$_{3/2}$-0$_{1/2}$)/HCN(1-0) ratio",
            size=1000/10,
            ylabel="log Ratio",
            xlim=xlim,
            ylim=[-0.8,0.6],
            )

        rdata = [data_cone_2nd-data_cone_hcn10,data_disk_2nd-data_disk_hcn10]
        self._plot_radial(
            self.outpng_radial3,
            r,
            rdata,
            "(c) Radial HNC(1-0)/HCN(1-0) ratio",
            size=1000/10,
            ylabel="log Ratio",
            xlim=xlim,
            ylim=[-0.8,-0.1],
            )

    def plot_hexmap_ratio(self,denom=None):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)

        # extract line name
        header,data_mom0,_,ra,dec,_ = self._read_table(self.table_hex_obs)
        data_denom = data_mom0[:,np.where(header==denom)[0][0]]

        # plot
        for i in range(len(header)):
            this_c = data_mom0[:,i] / data_denom
            this_c[np.where(np.isinf(this_c))] = 0
            this_c[np.where(np.isnan(this_c))] = 0
            this_name = header[i]

            this_x = ra[this_c>0]
            this_y = dec[this_c>0]
            this_c = this_c[this_c>0]

            this_c = np.log10(this_c)
            this_c[np.where(np.isinf(this_c))] = 0
            this_c[np.where(np.isnan(this_c))] = 0

            output = self.outpng_mom0.replace("???","r_"+this_name+"_"+denom)

            if len(this_c)!=0:
                print("# plot " + output)
                self._plot_hexmap(
                    output,
                    this_x,
                    this_y,
                    this_c,
                    this_name,
                    ann=False,
                    )

    def plot_hexmap_pca_podium(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_obs,taskname)
        factor = 2.0

        # extract mom0 data
        header,data_mom0,_,x,y,r = self._read_table(self.table_hex_obs)

        # get PC1 podium
        pc1_name1  = "h13cn10"
        pc1_name2  = "hc3n109"
        pc1_name3  = "hcn10"
        pc1_name4  = "13co10"

        pc1_index1 = np.where(header==pc1_name1)
        pc1_index2 = np.where(header==pc1_name2)
        pc1_index3 = np.where(header==pc1_name3)
        pc1_index4 = np.where(header==pc1_name4)

        pc1_z1     = np.array(data_mom0[:,pc1_index1].flatten())
        pc1_z2     = np.array(data_mom0[:,pc1_index2].flatten())
        pc1_z3     = np.array(data_mom0[:,pc1_index3].flatten())
        pc1_z4     = np.array(data_mom0[:,pc1_index4].flatten())

        pc1_z1     = np.where(r<=self.r_sbr_as,pc1_z1,0)
        pc1_z2     = np.where(r<=self.r_sbr_as,pc1_z2,0)
        pc1_z3     = np.where(r<=self.r_sbr_as,pc1_z3,0)
        pc1_z4     = np.where(r<=self.r_sbr_as,pc1_z4,0)

        pc1_z1     = np.where(pc1_z1>=np.max(pc1_z1)/factor, np.max(pc1_z1)/factor, pc1_z1)
        pc1_z2     = np.where(pc1_z2>=np.max(pc1_z2)/factor, np.max(pc1_z2)/factor, pc1_z2)
        pc1_z3     = np.where(pc1_z3>=np.max(pc1_z3)/factor, np.max(pc1_z3)/factor, pc1_z3)
        pc1_z4     = np.where(pc1_z4>=np.max(pc1_z4)/factor, np.max(pc1_z4)/factor, pc1_z4)

        # get PC1 podium
        pc2_name1  = "cn10h"
        pc2_name2  = "cch10"
        pc2_name3  = "hnc10"
        pc2_name4  = "c18o10"

        pc2_index1 = np.where(header==pc2_name1)
        pc2_index2 = np.where(header==pc2_name2)
        pc2_index3 = np.where(header==pc2_name3)
        pc2_index4 = np.where(header==pc2_name4)

        pc2_z1     = np.array(data_mom0[:,pc2_index1].flatten())
        pc2_z2     = np.array(data_mom0[:,pc2_index2].flatten())
        pc2_z3     = np.array(data_mom0[:,pc2_index3].flatten())
        pc2_z4     = np.array(data_mom0[:,pc2_index4].flatten())

        pc2_z1     = np.where(r<=self.r_sbr_as,pc2_z1,0)
        pc2_z2     = np.where(r<=self.r_sbr_as,pc2_z2,0)
        pc2_z3     = np.where(r<=self.r_sbr_as,pc2_z3,0)
        pc2_z4     = np.where(r<=self.r_sbr_as,pc2_z4,0)

        pc2_z1     = np.where(pc2_z1>=np.max(pc2_z1)/factor, np.max(pc2_z1)/factor, pc2_z1)
        pc2_z2     = np.where(pc2_z2>=np.max(pc2_z2)/factor, np.max(pc2_z2)/factor, pc2_z2)
        pc2_z3     = np.where(pc2_z3>=np.max(pc2_z3)/factor, np.max(pc2_z3)/factor, pc2_z3)
        pc2_z4     = np.where(pc2_z4>=np.max(pc2_z4)/factor, np.max(pc2_z4)/factor, pc2_z4)

        # PC1 podium+1
        self._plot_hexmap(
            self.outpng_pca1_mom0_1st,
            x,
            y,
            pc1_z1,
            "H$^{13}$CN(1-0) (highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        self._plot_hexmap(
            self.outpng_pca1_mom0_2nd,
            x,
            y,
            pc1_z2,
            "HC$_3$N(10-9) (2nd highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        self._plot_hexmap(
            self.outpng_pca1_mom0_3rd,
            x,
            y,
            pc1_z3,
            "HCN(1-0) (3rd highest PC1)",
            cmap="Reds",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        self._plot_hexmap(
            self.outpng_pca1_mom0_4th,
            x,
            y,
            pc1_z4,
            "$^{13}$CO(1-0) (lowest PC1)",
            cmap="Greys",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        # PC2 podium+1
        self._plot_hexmap(
            self.outpng_pca2_mom0_1st,
            x,
            y,
            pc2_z1,
            "CN(1-0)h (highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        self._plot_hexmap(
            self.outpng_pca2_mom0_2nd,
            x,
            y,
            pc2_z2,
            "CCH(1-0) (2nd highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        self._plot_hexmap(
            self.outpng_pca2_mom0_3rd,
            x,
            y,
            pc2_z3,
            "HNC(1-0) (3rd highest PC2)",
            cmap="PuBu",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

        self._plot_hexmap(
            self.outpng_pca2_mom0_4th,
            x,
            y,
            pc2_z4,
            "C$^{18}$O(1-0) (lowest PC2)",
            cmap="Greys",
            ann=True,
            add_text=False,
            lim=13,
            size=3600,
            label="(K km s$^{-1}$)",
            )

    def plot_hexmap_pca_r13co(self):
        """
        """

        taskname = self.modname + sys._getframe().f_code.co_name
        check_first(self.table_hex_pca_r13co,taskname)

        # extract mom0 data
        data = np.loadtxt(self.table_hex_pca_r13co)
        x        = data[:,0]
        y        = data[:,1]
        r        = np.sqrt(x**2 + y**2)
        data_pca = data[:,2:]

        ###################
        # plot PC scatter #
        ###################
        print("# plot " + self.outpng_pca_scatter_r13co)

        table_hex_pca_score = self.table_hex_pca_r13co.replace(".txt","_score.txt")
        data_score = np.loadtxt(table_hex_pca_score,dtype="str")
        score_name = data_score[:,0]
        score_pc1  = data_score[:,1].astype(np.float64)
        score_pc2  = data_score[:,2].astype(np.float64)
        score_pc1  = score_pc1 / np.std(score_pc1)
        score_pc2  = score_pc2 / np.std(score_pc2)

        # set plt, ax
        fig = plt.figure(figsize=(13,10))
        plt.rcParams["font.size"] = 16
        gs = gridspec.GridSpec(nrows=10, ncols=10)
        ax = plt.subplot(gs[0:10,0:10])

        # set ax parameter
        myax_set(
        ax,
        grid=None,
        xlim=[-3.2,1.8],
        ylim=[-1.6,3.4],
        xlabel="PC1",
        ylabel="PC2",
        adjust=[0.023,0.963,0.10,0.93],
        )
        ax.set_aspect('equal', adjustable='box')

        for i in range(len(score_name)):
            pc1 = score_pc1[i]
            pc2 = score_pc2[i]
            ax.plot([0,pc1],[0,pc2],"-",color="grey",lw=2)

            """
            if score_name[i]=="n2hp10":
                ax.text(pc1,pc2,"N$_2$H$^+$",fontsize=18,ha="center",va="top")
            elif score_name[i]=="hc3n109":
                continue
            elif score_name[i]=="hc3n1110":
                continue
            elif score_name[i]=="hc3n1211":
                ax.text(pc1,pc2-0.15,"HC$_3$Nx3",fontsize=18,ha="left",va="center")
            elif score_name[i]=="h13cn10":
                ax.text(pc1,pc2-0.1,"H$^{13}$CN",fontsize=18,ha="left",va="bottom")
            elif score_name[i]=="cs21":
                ax.text(pc1,pc2,"CS",fontsize=18,ha="center",va="top")
            elif score_name[i]=="hcn10":
                ax.text(pc1,pc2,"HCN",fontsize=18,ha="left",va="center")
            elif score_name[i]=="hcop10":
                ax.text(pc1,pc2,"HCO$^+$",fontsize=18,ha="left",va="center")
            elif score_name[i]=="cn10l":
                ax.text(pc1,pc2,"CN(1-0)l",fontsize=18,ha="left",va="center")
            elif score_name[i]=="hnc10":
                ax.text(pc1,pc2,"HNC",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="cn10h":
                ax.text(pc1,pc2,"CN(1-0)h",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="ci10":
                ax.text(pc1,pc2,"[CI]",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="cch10":
                ax.text(pc1,pc2,"CCH",fontsize=18,ha="right",va="bottom")
            elif score_name[i]=="siiisii_ratio":
                ax.text(pc1,pc2,"[SIII]/[SII] ratio",fontsize=18,ha="center",va="bottom")
            elif score_name[i]=="co10":
                ax.text(pc1,pc2,"CO",fontsize=18,ha="right",va="center")
            elif score_name[i]=="13co10":
                ax.text(pc1,pc2,"$^{13}$CO",fontsize=18,ha="right",va="center")
            elif score_name[i]=="c18o10":
                ax.text(pc1,pc2,"C$^{18}$O",fontsize=18,ha="right",va="center")
            elif score_name[i]=="ch3oh21":
                ax.text(pc1,pc2,"CH$_3$OH",fontsize=18,ha="center",va="top")
            else:
            """
            ax.text(pc1,pc2,score_name[i],fontsize=14)

        ax.text(0.03, 0.93, "PC1 vs. PC2", color="black", transform=ax.transAxes, weight="bold", fontsize=24)

        # save
        os.system("rm -rf " + self.outpng_pca_scatter_r13co)
        plt.savefig(self.outpng_pca_scatter_r13co, dpi=300)

        #################
        # plot PCA maps #
        #################
        anntexts = [True,False]
        cmaps    = ["Reds","PuBu"]
        for i in range(len(data_pca[0])):
            this_c    = data_pca[:,i]
            this_x    = x[this_c!=0]
            this_y    = y[this_c!=0]
            this_c    = this_c[this_c!=0]
            this_text = anntexts[i]
            thid_cmap = cmaps[i]

            if abs(np.min(this_c))>abs(np.max(this_c)):
                this_c = this_c * -1

            this_c = np.where(this_c>np.max(this_c)/1.5,np.max(this_c)/1.5,this_c)

            output = self.outpng_pca_hexmap_r13co.replace("???",str(i+1))

            print("# plot " + output)
            self._plot_hexmap(
                output,
                this_x,
                this_y,
                this_c,
                "PC"+str(i+1)+" (intensity normalized to $^{13}$CO)",
                cmap=thid_cmap,
                ann=True,
                add_text=this_text,
                lim=13,
                size=3600,
                )

    def _plot_radial(
        self,
        outpng,
        r,clist,
        title,
        size=100,
        ylabel=None,
        xlim=None,
        ylim=None,
        ann=None,
        fvalue=1/3.0,
        ):
        """
        """

        # set plt, ax
        fig = plt.figure(figsize=(13,10))
        plt.rcParams["font.size"] = 16
        gs = gridspec.GridSpec(nrows=10, ncols=10)
        ax = plt.subplot(gs[0:10,0:10])

        # set ax parameter
        myax_set(
        ax,
        grid="both",
        xlim=xlim,
        ylim=ylim,
        xlabel="Distance (arcsec)",
        ylabel=ylabel,
        adjust=[0.176,0.813,0.10,0.93],
        )

        zorder = 1e9
        # plot data
        for i in range(len(clist)):
            this_c = clist[i]
            this_zorder = zorder / float(i+1)

            # constrain data
            this_c[np.isnan(this_c)] = -100
            this_c[np.isinf(this_c)] = -100
            cut    = np.where((this_c!=-100) & (this_c!=0))
            this_c = this_c[cut]
            this_r = r[cut]

            # plot data
            if i==0:
                color = "tomato"
            elif i==1:
                color = "deepskyblue"

            # plot LOWESS
            order  = np.argsort(this_r)
            y_sm, y_std = lowess(this_r, this_c, f=fvalue)
            ax.plot(this_r[order], y_sm[order], color=color, lw=8, zorder=this_zorder)
            plt.fill_between(this_r[order], y_sm[order] - y_std[order],
                y_sm[order] + y_std[order], lw=0, color=color, alpha=0.5, zorder=this_zorder)

        # text
        ax.text(0.03, 0.93, title, color="black", transform=ax.transAxes, weight="bold", fontsize=24)

        # annotation
        if ann==1:
            ax.text(0.97, 0.93, "Bicone", color="tomato", transform=ax.transAxes, fontsize=24, ha="right", weight="bold")
            ax.text(0.97, 0.87, "Disk", color="deepskyblue", transform=ax.transAxes, fontsize=24, ha="right", weight="bold")
        if ann==2:
            ax.text(0.97, 0.93, "CN(1$_{3/2}$-0$_{1/2}$)/HCN(1-0)", color=cm.rainbow(0/float(len(clist)-1)), transform=ax.transAxes, fontsize=24, ha="right")
            ax.text(0.97, 0.87, "HNC(1-0)/HCN(1-0)", color=cm.rainbow(1/float(len(clist)-1)), transform=ax.transAxes, fontsize=24, ha="right")
            ax.text(0.97, 0.81, "CCH(1-0)/HCN(1-0)", color=cm.rainbow(2/float(len(clist)-1)), transform=ax.transAxes, fontsize=24, ha="right")

        # save
        os.system("rm -rf " + outpng)
        plt.savefig(outpng, dpi=300)

    def _get_bicone_radial(
        self,
        name,
        cone="in",
        ):
        """
        """

        offset = 10
        angle1 = -15 - offset
        angle2 = -115 + offset
        angle3 = 165 - offset
        angle4 = 65 + offset

        # get table
        header,data_mom0,_,x,y,r = self._read_table(self.table_hex_obs)
        theta_deg  =  np.degrees(np.arctan2(x, y))

        # get line data
        line_index = np.where(header==name)
        data_line  = np.array(data_mom0[:,line_index].flatten())
        data_line[np.isinf(data_line)] = 0
        data_line[np.isnan(data_line)] = 0
        data_line  = np.where(r<=self.r_sbr_as,data_line,0)

        # get line bicone
        line_zc    = np.where(r<1,data_line,0)
        line_zn    = np.where((theta_deg>=angle1)&(theta_deg<angle4)&(r<self.r_sbr_as),data_line,0)
        line_zs    = np.where((theta_deg>=angle3)&(r<self.r_sbr_as),data_line,0)
        line_zs    = np.where((theta_deg<angle2)&(r<self.r_sbr_as),data_line,line_zs)

        if cone=="in":
            data_line = np.log10(line_zn + line_zs + line_zc)
        elif cone=="out":
            data_line = np.log10(data_line - line_zn - line_zs)

        return data_line, r

###################
# end of ToolsPCA #
###################


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Feb  5 20:21:28 2019

@author: rafaelolaechea
"""
import pickleFacade

def summarizeTracesX264SpecialFromResults(pklOuptputFilename, baseFilenameTemplate="news/results/rq2_predictions_rep_{0}.csv"):
    """
    Summarize Traces X264 from both results and from reading through traces (for the configurations in the training set)

    Get Input data for files News and Container.
    """

    dctAllTracesExecutionTimes = {}
    showNextInserts = False
    for testTrainSplit in range(1, 11):
        fdFilename = baseFilenameTemplate.format(testTrainSplit)
        print("Starting openning {0}".format(fdFilename))
        fdAll = open(fdFilename, "r")
        lineIndex = 0

        seenConfigurations = 0

        for line in fdAll:
            if lineIndex == 0:
                lineIndex = lineIndex + 1
                continue

            splitInParts = line.strip().split(",")
            if lineIndex == 18440  and testTrainSplit == 1:
                print (splitInParts)

            confId, timeTaken = splitInParts[0], splitInParts[1]

            if (int(confId), (seenConfigurations+1)) not in dctAllTracesExecutionTimes.keys():
                seenConfigurations = seenConfigurations + 1
                if showNextInserts:
                    print ("Will insert {0}--{1}".format(confId, seenConfigurations))
                dctAllTracesExecutionTimes[(int(confId), seenConfigurations)] = float(timeTaken)
                if seenConfigurations == 10:
                    seenConfigurations = 0

            lineIndex = lineIndex + 1
            if lineIndex == 18441 :
                break

        print ("After full search we have  {0} keys".format(len(dctAllTracesExecutionTimes.keys())))

        if len(dctAllTracesExecutionTimes.keys()) >= 23030 :
            showNextInserts = True
    for a,b in dctAllTracesExecutionTimes.keys():
        if (a not in range(0, 2304)) and (b not in range(1, 11)):
            print ("a={0} b={1}".format(a,b))

    pickleFacade.saveObjectToPickleFile(pklOuptputFilename, dctAllTracesExecutionTimes)

if __name__ == "__main__":
    print ("Started Reading")
    summarizeTracesX264SpecialFromResults("news/traceExecutionTimesForAll.pkl")
    print ("Finished Reading")


from pathlib import Path
from datetime import datetime
import matplotlib.pyplot as plt
import csv

path = Path('chapter16\san_francisco (16.3)\san_francisco_weather_2021.csv')
lines = path.read_text().splitlines()

reader = csv.reader(lines)
header_column = next(reader)

for index, column in enumerate(header_column):
    print(index, column)

# extract information -- DATE, TMAX, TMIN

dates, highs, lows = [], [], []

for row in reader:
    try:
        date = datetime.strptime(row[2], '%Y-%m-%d')
        high = int(row[3])
        low = int(row[4])
    except ValueError:
        print("Missing data in %s", date)
    else:
        dates.append(date)
        highs.append(high)
        lows.append(low)

# visualize data using matplotlib

plt.style.use('classic')
fig, ax = plt.subplots()
ax.plot(dates, highs, color='red', alpha=0.3)
ax.plot(dates, lows, color='blue', alpha=0.3)
plt.fill_between(dates, highs, lows, alpha=0.1)

# format graph
ax.set_title("High & Low Air Temperature in San Francisco 2021", fontsize=24)
plt.ylim(0, 100)
fig.autofmt_xdate
ax.set_ylabel("Temperature (F)", fontsize=16)
ax.tick_params(axis='both', labelsize=16)

plt.show()


'''
Assignment
Complete the Archer class.

Constructor
The constructor should take and set as properties the following parameters in order:

num_arrows
health
name
get_shot method
Create a method called get_shot that doesn't take any parameters.

If the current archer has health left it removes one health from the current archer.
Then, if the archer's health is 0 it prints the string: {} is dead where {} is the archer's name.

shoot method
Create a method called shoot that takes a target archer as input.

If the shooter has no arrows left, raise the exception {} can't shoot where {} is the archer's name.
Otherwise, remove an arrow from the shooter and print {1} shoots {2} where {1} is the shooter's name and {2} is the name of the target.
Next, call the target's get_shot() method.
'''

class Archer:
    def __init__(self, num_arrows, health, name):
        self.num_arrows = num_arrows
        self.health = health
        self.name = name

    def get_shot(self):
        if self.health >= 1:
            self.health -= 1
        else:
            print(f"{self.name} is dead")

    def shoot(self, target):
        if self.num_arrows >= 1:
            self.num_arrows -= 1
            print(f"{self.name} shoots {target.name}")
            target.get_shot()
        else:
            print(f"{self.name} can't shoot")


from tracardi.service.plugin.domain.register import Plugin, Spec, MetaData, Documentation, PortDoc, Form, FormGroup, \
    FormField, FormComponent
from tracardi.service.plugin.domain.result import Result
from tracardi.service.plugin.runner import ActionRunner
from tracardi.service.storage.driver.elastic import resource as resource_db
from .model.config import Config, APIKey
from ..client import AirtableClient, AirtableClientException
from tracardi.service.notation.dot_template import DotTemplate

def validate(config: dict) -> Config:
    return Config(**config)

class FetchFromAirtableAction(ActionRunner):

    client: AirtableClient
    config: Config

    async def set_up(self, init):
        config = Config(**init)
        resource = await resource_db.load(config.source.id)

        self.config = config
        self.client = AirtableClient(token=resource.credentials.get_credentials(self, APIKey).api_key)
        self.client.set_retries(self.node.on_connection_error_repeat)

    async def run(self, payload: dict, in_edge=None) -> Result:
        dot = self._get_dot_accessor(payload)
        template = DotTemplate()

        formula = template.render(self.config.formula, dot) if self.config.formula is not None else None

        try:
            result = await self.client.get_records(self.config.base_id, self.config.table_name, formula)
            return Result(port="response", value=result)

        except AirtableClientException as e:
            return Result(port="error", value={"error": str(e)})

def register() -> Plugin:
    return Plugin(
        start=False,
        spec=Spec(
            module=__name__,
            className='FetchFromAirtableAction',
            inputs=["payload"],
            outputs=["response", "error"],
            version='0.6.2',
            license="MIT",
            author="Dawid Kruk",
            manual="fetch_from_airtable_action",
            init={
                "source": {
                    "name": None,
                    "id": None
                },
                "base_id": None,
                "table_name": None,
                "formula": None
            },
            form=Form(
                groups=[
                    FormGroup(
                        name="Plugin configuration",
                        fields=[
                            FormField(
                                id="source",
                                name="Airtable resource",
                                description="Please select your Airtable resource, containing your Airtable API key.",
                                component=FormComponent(type="resource", props={"label": "Resource", "tag": "airtable"})
                            ),
                            FormField(
                                id="base_id",
                                name="Base ID",
                                description="Please provide ID of the base that contains your table. You can find it "
                                            "in the URL when inspecting the base. (https://airtable.com/<BASE-ID>/...)",
                                component=FormComponent(type="text", props={"label": "Base ID"})
                            ),
                            FormField(
                                id="table_name",
                                name="Table name",
                                description="Please provide the exact name of the table that you want to fetch records "
                                            "from",
                                component=FormComponent(type="text", props={"label": "Table"})
                            ),
                            FormField(
                                id="formula",
                                name="Formula",
                                description="Please provide a formula that you want to filter your records by. "
                                            "(e.g. {profileID} = {{profile@id}} ). This parameter supports templates "
                                            "and is fully optional.",
                                component=FormComponent(type="textarea", props={"label": "Formula"})
                            )
                        ]
                    )
                ]
            )
        ),
        metadata=MetaData(
            name='Fetch data',
            desc='Fetches data from given Airtable table, according to given query.',
            icon='airtable',
            group=["AirTable"],
            documentation=Documentation(
                inputs={
                    "payload": PortDoc(desc="This port takes payload object.")
                },
                outputs={
                    "response": PortDoc(desc="This port returns a response from Airtable if everything is OK."),
                    "error": PortDoc(desc="This port returns some error info if anything goes wrong.")
                }
            )
        )
    )


filename = "../Datasets/dataset_9_4.txt"

with open(filename, 'r') as file:
    genome = file.read()

#genome = "CGCCCGAATCCAGAACGCATTCCCATATTTCGGGACCACTGGCCTCCACGGTACGGACGTCAATCAAAT"
pattern = "GAGGCACTGTAG"
d = 5
position = []

def approx_pat(pattern, genome, d):
    for i in range (len(genome) - len(pattern)+1):
        if hamming_distance(pattern, genome[i:i + len(pattern)]) <= int(d):
            position.append(i)
    return position

def hamming_distance(q, p):
        dist = 0
        for i in range(len(p)):
            if p[i] != q[i]:
                dist += 1
        return dist

data = approx_pat(pattern, genome, d)

for i in range(0,len(data)):
    print(data[i])


import math

code=int(input("Please enter the code recorded at the begining of the experiment: "))

n=code
def primeFactors(n):
    fact=[]
    while n % 2 == 0:
        fact.append(2)
        n = n / 2
    for i in range(3,int(math.sqrt(n))+1,2):
            while n % i== 0:
                fact.append(i)
                n = n / i
    if n > 2:
        fact.append(n)
    return(fact)

a=[11, 13, 17, 19, "Row A"]
b=[23, 29, 31, 37, "Row B"]
c=[41, 43, 47, 53,"Row C"]
d=[59, 61, 67, 71,"Row D"]

randomiser=[103, 107, 109, 113, 127, 131, 137, 139, 149, 151]

factored=primeFactors(code)
factored.sort()
output=''

for i in range(len(factored)):
    if factored[i] in a:
        output+=a[4]+" And "
    if factored[i] in b:
        output+=b[4]+" And "
    if factored[i] in c:
        output+=c[4]+" Were The Rows With Noxious Stimuli. All The Best"
    if factored[i] in d:
        output+=d[4]+" Were The Rows With Noxious Stimuli. All The Best"

print(output)