Пример #1
0
def ref_fk4_no_e_fk5(fnout='fk4_no_e_fk5.csv'):
    """
    Accuracy tests for the FK4 (with no E-terms of aberration) to/from FK5
    conversion, with arbitrary equinoxes and epoch of observation.
    """

    import starlink.Ast as Ast

    np.random.seed(12345)

    N = 200

    # Sample uniformly on the unit sphere. These will be either the FK4
    # coordinates for the transformation to FK5, or the FK5 coordinates for the
    # transformation to FK4.
    ra = np.random.uniform(0., 360., N)
    dec = np.degrees(np.arcsin(np.random.uniform(-1., 1., N)))

    # Generate random observation epoch and equinoxes
    obstime = [f"B{x:7.2f}" for x in np.random.uniform(1950., 2000., N)]
    equinox_fk4 = [f"B{x:7.2f}" for x in np.random.uniform(1925., 1975., N)]
    equinox_fk5 = [f"J{x:7.2f}" for x in np.random.uniform(1975., 2025., N)]

    ra_fk4, dec_fk4 = [], []
    ra_fk5, dec_fk5 = [], []

    for i in range(N):

        # Set up frames for AST
        frame_fk4 = Ast.SkyFrame(
            'System=FK4-NO-E,Epoch={epoch},Equinox={equinox_fk4}'.format(
                epoch=obstime[i], equinox_fk4=equinox_fk4[i]))
        frame_fk5 = Ast.SkyFrame(
            'System=FK5,Epoch={epoch},Equinox={equinox_fk5}'.format(
                epoch=obstime[i], equinox_fk5=equinox_fk5[i]))

        # FK4 to FK5
        frameset = frame_fk4.convert(frame_fk5)
        coords = np.degrees(
            frameset.tran([[np.radians(ra[i])], [np.radians(dec[i])]]))
        ra_fk5.append(coords[0, 0])
        dec_fk5.append(coords[1, 0])

        # FK5 to FK4
        frameset = frame_fk5.convert(frame_fk4)
        coords = np.degrees(
            frameset.tran([[np.radians(ra[i])], [np.radians(dec[i])]]))
        ra_fk4.append(coords[0, 0])
        dec_fk4.append(coords[1, 0])

    # Write out table to a CSV file
    t = Table()
    t.add_column(Column(name='equinox_fk4', data=equinox_fk4))
    t.add_column(Column(name='equinox_fk5', data=equinox_fk5))
    t.add_column(Column(name='obstime', data=obstime))
    t.add_column(Column(name='ra_in', data=ra))
    t.add_column(Column(name='dec_in', data=dec))
    t.add_column(Column(name='ra_fk5', data=ra_fk5))
    t.add_column(Column(name='dec_fk5', data=dec_fk5))
    t.add_column(Column(name='ra_fk4', data=ra_fk4))
    t.add_column(Column(name='dec_fk4', data=dec_fk4))
    f = open(os.path.join('data', fnout), 'wb')
    f.write("# This file was generated with the {} script, and the reference "
            "values were computed using AST\n".format(
                os.path.basename(__file__)))
    t.write(f, format='ascii', delimiter=',')
Пример #2
0
except (IOError):
   plot_atts = ""

#  Attempt to open an associated file holding the pixel bounds of the
#  area of the FITS array to be plotted.
try:
   fin2 = open( sys.argv[1]+".box" )
   box = [float(v) for v in fin2.read().strip().split()]
   fin2.close()
except (IOError):
   box = None

#  Read the header lines into a list, and store this list in a new
#  Ast.FitsChan, using the requested attributes to modify the
#  interpretation of the header.
fc = Ast.FitsChan( fin1.readlines(), None, fits_atts )

#  Close the header file.
fin1.close()

#  Create a FrameSet from the FITS headers in the FitsChan.
fs = fc.read()
if fs == None:
   print( "Could not read WCS from headers in "+sys.argv[1]+".head" )
   sys.exit(2)

#  Exit if the header does not have exactly 2 pixel axes and 2 WCS axes.
if fs.Nin != 2 or fs.Nout != 2:
   print( "The headers in "+sys.argv[1]+".head do not describe a 2-D image" )
   sys.exit(2)
Пример #3
0
def ref_galactic_fk4(fnout='galactic_fk4.csv'):
    """
    Accuracy tests for the ICRS (with no E-terms of aberration) to/from FK5
    conversion, with arbitrary equinoxes and epoch of observation.
    """

    import starlink.Ast as Ast

    np.random.seed(12345)

    N = 200

    # Sample uniformly on the unit sphere. These will be either the ICRS
    # coordinates for the transformation to FK5, or the FK5 coordinates for the
    # transformation to ICRS.
    lon = np.random.uniform(0., 360., N)
    lat = np.degrees(np.arcsin(np.random.uniform(-1., 1., N)))

    # Generate random observation epoch and equinoxes
    obstime = [f"B{x:7.2f}" for x in np.random.uniform(1950., 2000., N)]
    equinox_fk4 = [f"J{x:7.2f}" for x in np.random.uniform(1975., 2025., N)]

    lon_gal, lat_gal = [], []
    ra_fk4, dec_fk4 = [], []

    for i in range(N):

        # Set up frames for AST
        frame_gal = Ast.SkyFrame(f'System=Galactic,Epoch={obstime[i]}')
        frame_fk4 = Ast.SkyFrame(
            f'System=FK4,Epoch={obstime[i]},Equinox={equinox_fk4[i]}')

        # ICRS to FK5
        frameset = frame_gal.convert(frame_fk4)
        coords = np.degrees(
            frameset.tran([[np.radians(lon[i])], [np.radians(lat[i])]]))
        ra_fk4.append(coords[0, 0])
        dec_fk4.append(coords[1, 0])

        # FK5 to ICRS
        frameset = frame_fk4.convert(frame_gal)
        coords = np.degrees(
            frameset.tran([[np.radians(lon[i])], [np.radians(lat[i])]]))
        lon_gal.append(coords[0, 0])
        lat_gal.append(coords[1, 0])

    # Write out table to a CSV file
    t = Table()
    t.add_column(Column(name='equinox_fk4', data=equinox_fk4))
    t.add_column(Column(name='obstime', data=obstime))
    t.add_column(Column(name='lon_in', data=lon))
    t.add_column(Column(name='lat_in', data=lat))
    t.add_column(Column(name='ra_fk4', data=ra_fk4))
    t.add_column(Column(name='dec_fk4', data=dec_fk4))
    t.add_column(Column(name='lon_gal', data=lon_gal))
    t.add_column(Column(name='lat_gal', data=lat_gal))
    f = open(os.path.join('data', fnout), 'wb')
    f.write("# This file was generated with the {} script, and the reference "
            "values were computed using AST\n".format(
                os.path.basename(__file__)))
    t.write(f, format='ascii', delimiter=',')
Пример #4
0
#  Use pyfits to open a test files file
ffile = pyfits.open('starlink/ast/test/cobe.fit')

#  Use matplotlib to plot an annotated grid of the WCS coords
Atl.plotfitswcs(
    matplotlib.pyplot.figure(figsize=(8, 8)).add_subplot(111),
    [0.1, 0.1, 0.9, 0.9], ffile)
matplotlib.pyplot.show()

#  Create a FitsChan telling it to use the pyfits primary hdu as the
#  external data source and sink. Note, we take the default value of
#  "True" for the "clear" property when creating the PyFITSADapater,
#  which means the PyFITS header will be cleared immediately before
#  the FitsChan.writefits() method writes to it.
adapter = Atl.PyFITSAdapter(ffile)
fc = Ast.FitsChan(adapter, adapter)

#  Read the FrameSet from the FitsChan. This will read all headers from
#  the pyfits hdu into the FitsChan, create a FrameSet from the WCS
#  headers, and remove all WCS-related headers from the FitsChan (but not
#  the pyfits primary hdu as yet).
fs = fc.read()

#  Tell the FitsChan to write out the remaining headers to its external data
#  sink.
fc.writefits()

#  Display the headers now in the pyfits primary hdu.
print()
print("The non-WCS cards in cobe.fit: ")
for v in ffile[0].header.cards:
Пример #5
0
    def run(self):

        # Get the names of library files Name of shared object
        # library, and ensure -bundle isn't called in linking on osx.
        libtype = 'shared'
        rdirs = ['$ORIGIN']
        ldirs = []
        ext_runtime_library_dirs = '$ORIGIN/{}'
        ext_extra_link_args = None
        osx = None
        if 'osx' in self.plat_name or 'darwin' in self.plat_name:
            osx = True
            print('\n\nBuilding under OSX!\n\n\n')
            libtype = 'dylib'
            from distutils import sysconfig
            vars = sysconfig.get_config_vars()
            vars['LDSHARED'] = vars['LDSHARED'].replace(
                '-bundle', '-dynamiclib')
            rdirs = []
            ldirs = ['-Wl,-rpath,' + '@loader_path/']
            ldirs = []
            ext_runtime_library_dirs = None
            ext_extra_link_args = '-Wl,-rpath,@loader_path/{}'
            install_name_pattern = '-Wl,-install_name,@rpath/{}'
        # Ensure the directories and files are in appropriate locations.
        setup_building()

        # Before we can build the extensions, we have to run ./configure
        # and make for HDF5.
        basedir = os.getcwd()
        os.chdir('hdf5')
        env = os.environ
        if not FAKEBUILDING:
            subprocess.check_call('./configure', env=env)
            subprocess.check_call('make', env=env)
        os.chdir(basedir)

        #Now we need to get the header files we need copied into our
        #output directory.
        if not os.path.isdir('include'):
            os.mkdir('include')
        if not os.path.isdir(os.path.join('include', 'star')):
            os.mkdir(os.path.join('include', 'star'))

        # Copy hdf5 needed header files over.
        shutil.copy(os.path.join('hdf5', 'src', 'hdf5.h'), 'include')
        shutil.copy(os.path.join('hdf5', 'src', 'H5public.h'), 'include')
        shutil.copy(os.path.join('hdf5', 'src', 'H5pubconf.h'), 'include')
        shutil.copy(os.path.join('hdf5', 'src', 'H5version.h'), 'include')

        # Get the sources for the ndf and hds dependencies.
        hds_source_dep = []
        for name_ in HDS_DEP_LIBS:
            hds_source_dep += get_source(name_)

        ndf_source_dep = []
        for name_ in ['prm', 'ast', 'ary']:
            ndf_source_dep += get_source(name_)


        hdsex_includedirs = ['include', 'hds', 'missingincludes',
                             'hds_missingincludes', os.path.join('hdf5','src'), os.path.join('hdf5','hl','src')] + \
            ['starutil', 'starmem', 'cnf', 'ems', 'mers', 'chr',\
             'one'] + \
            [numpy.get_include()]

        from starlink import Ast
        ndfex_includedirs = hdsex_includedirs + [
            'prm', 'ast', 'ary', 'ast_missingincludes',
            Ast.get_include()
        ]

        define_macros = get_starlink_macros(osx=osx)

        # Now build all.

        # This is the directory where the extra library's built here
        # have to be copied to, relative to the final build. This must
        # be called '.libs' if you want to use this with
        # cibuildwheel/auditwheel.
        extra_lib_dir = '.libs'

        # Get the compilers.
        compiler = ccompiler.new_compiler(dry_run=FAKEBUILDING, verbose=0)
        compiler2 = ccompiler.new_compiler(verbose=1)

        # Ensure we have any distutils options set.
        customize_compiler(compiler)
        customize_compiler(compiler2)

        # Now go through each extension, build the shared libraries we
        # need and ensure they are copied to the build directory. We
        # will use rpath and $ORIGIN to ensure everything is portable
        # as it will be moved around during the build process by pip
        # etc.
        for ext in self.extensions:
            linked_libraries = []
            if ext.name == 'starlink.hds':

                hds_deps = compiler.compile(
                    sources=hds_source_dep,
                    output_dir=OUTPUTDIR,
                    macros=define_macros,
                    include_dirs=HDS_DEP_INCLUDES,
                    depends=hds_source_dep,
                )
                hds_deps_libname = compiler2.library_filename('pyhdsdeps',
                                                              lib_type=libtype)
                # Build this into a library

                print('Linking HDSDEPS\n\n\n')
                extra_preargs = None
                if osx:
                    extra_preargs = [
                        '-v', '-Wl,-v',
                        install_name_pattern.format(hds_deps_libname)
                    ]

                compiler2.link('shared',
                               hds_deps,
                               hds_deps_libname,
                               output_dir=OUTPUTDIR,
                               extra_preargs=extra_preargs,
                               extra_postargs=None)
                linked_libraries += [os.path.join(OUTPUTDIR, hds_deps_libname)]

                # Now build hds-v4 and hds-v5: have to do this separately.
                hdsv4_libname = compiler.library_filename('pyhdsv4',
                                                          lib_type=libtype)
                hdsv4objs = compiler.compile(
                    sources=get_source('hds-v4'),
                    output_dir=OUTPUTDIR,
                    macros=define_macros,
                    include_dirs=('hds-v4_missingincludes', ) +
                    HDS_DEP_INCLUDES,
                    depends=get_source('hds-v4'))
                extra_preargs = None
                if osx:
                    extra_preargs = [
                        install_name_pattern.format(hdsv4_libname)
                    ]
                print('Linking HDSV4\n\n\n')
                compiler2.link('shared',
                               hdsv4objs,
                               hdsv4_libname,
                               output_dir=OUTPUTDIR,
                               extra_preargs=extra_preargs,
                               target_lang='c')
                linked_libraries += [os.path.join(OUTPUTDIR, hdsv4_libname)]
                print('CREATING HDF5 LIBRARY\n\n\n')
                # Create the HDF5 library
                hdf5_libpath = os.path.join('hdf5', 'src', '.libs')
                hdf5_objects = glob.glob(os.path.join(hdf5_libpath, '*.o'))
                hdf5_libname = compiler.library_filename('pystarhdf5',
                                                         lib_type=libtype)

                extra_preargs = None
                if osx:
                    extra_preargs = [install_name_pattern.format(hdf5_libname)]
                compiler2.link('shared',
                               hdf5_objects,
                               hdf5_libname,
                               output_dir=OUTPUTDIR,
                               library_dirs=[OUTPUTDIR],
                               runtime_library_dirs=rdirs,
                               extra_postargs=ldirs,
                               extra_preargs=extra_preargs)
                linked_libraries += [os.path.join(OUTPUTDIR, hdf5_libname)]

                hdsv5_libname = compiler2.library_filename('pyhdsv5',
                                                           lib_type=libtype)
                hdsv5objs = compiler.compile(
                    sources=get_source('hds-v5'),
                    output_dir=OUTPUTDIR,
                    macros=define_macros,
                    include_dirs=('hds-v5_missingincludes', ) +
                    HDS_DEP_INCLUDES,
                    depends=get_source('hds-v5'))
                extra_preargs = None
                if osx:
                    extra_preargs = [
                        install_name_pattern.format(hdsv5_libname)
                    ]

                compiler2.link('shared',
                               hdsv5objs,
                               hdsv5_libname,
                               output_dir=OUTPUTDIR,
                               libraries=['pystarhdf5'],
                               library_dirs=[OUTPUTDIR],
                               runtime_library_dirs=rdirs,
                               extra_postargs=ldirs,
                               extra_preargs=extra_preargs)
                linked_libraries += [os.path.join(OUTPUTDIR, hdsv5_libname)]

                hds_libname = compiler2.library_filename('pyhds',
                                                         lib_type=libtype)
                hdsobjs = compiler.compile(sources=get_source('hds'),
                                           output_dir=OUTPUTDIR,
                                           macros=define_macros,
                                           include_dirs=hdsex_includedirs,
                                           depends=get_source('hds'))
                extra_preargs = None
                if osx:
                    extra_preargs = [install_name_pattern.format(hds_libname)]

                compiler2.link('shared',
                               hdsobjs,
                               hds_libname,
                               output_dir=OUTPUTDIR,
                               libraries=['pyhdsdeps', 'pyhdsv5', 'pyhdsv4'],
                               library_dirs=[OUTPUTDIR],
                               runtime_library_dirs=rdirs,
                               extra_postargs=ldirs,
                               extra_preargs=extra_preargs)
                linked_libraries += [os.path.join(OUTPUTDIR, hds_libname)]

                ext.libraries += ['pyhds']
                ext.library_dirs += [OUTPUTDIR]
                if ext_runtime_library_dirs:
                    ext.runtime_library_dirs += [
                        ext_runtime_library_dirs.format(extra_lib_dir)
                    ]
                if ext_extra_link_args:
                    ext.extra_link_args += [
                        ext_extra_link_args.format(extra_lib_dir)
                    ]

            if ext.name == 'starlink.ndf':
                ndf_libname = compiler2.library_filename('pyndf',
                                                         lib_type=libtype)
                ndfobjs = compiler.compile(
                    sources=get_source('ndf') + ndf_source_dep,
                    include_dirs=['ndf/', 'ndf_missingincludes/'] +
                    ndfex_includedirs,
                    macros=define_macros,
                    depends=get_source('ndf'))
                extra_preargs = None
                if osx:
                    extra_preargs = [install_name_pattern.format(ndf_libname)]
                compiler2.link(
                    'shared',
                    ndfobjs,
                    ndf_libname,
                    output_dir=OUTPUTDIR,
                    libraries=['pyhdsdeps', 'pyhdsv5', 'pyhdsv4', 'pyhds'],
                    library_dirs=[OUTPUTDIR],
                    runtime_library_dirs=rdirs,
                    extra_postargs=ldirs,
                    extra_preargs=extra_preargs)
                linked_libraries += [os.path.join(OUTPUTDIR, ndf_libname)]
                ext.libraries += ['pyndf']
                ext.library_dirs += [OUTPUTDIR]
                if ext_runtime_library_dirs:
                    ext.runtime_library_dirs += [
                        ext_runtime_library_dirs.format(extra_lib_dir)
                    ]
                if ext_extra_link_args:
                    ext.extra_link_args += [
                        ext_extra_link_args.format(extra_lib_dir)
                    ]

            # Copy over the libraries to the build directory manually, and add to package data.
            if not os.path.isdir(
                    os.path.join(self.build_lib, 'starlink', extra_lib_dir)):
                os.mkdir(
                    os.path.join(self.build_lib, 'starlink', extra_lib_dir))

            for lib in linked_libraries:
                shutil.copy(
                    lib, os.path.join(self.build_lib, 'starlink',
                                      extra_lib_dir))
                output_lib = os.path.join('starlink', extra_lib_dir,
                                          os.path.split(lib)[1])
                self.distribution.package_data.get('starlink',
                                                   list()).extend(output_lib)

        # Run the standard build_ext process.
        build_ext.run(self)
Пример #6
0
    def __init__(self,
                 ast_object: starlink.Ast.Circle = None,
                 frame=None,
                 center: Iterator = None,
                 edge_point=None,
                 radius: [float, astropy.units.quantity.Quantity] = None):
        '''
		Parameters
		----------
		centerPoint : `numpy.ndarray`, list, tuple
			Two elements that describe the center point of the circle in the provided frame in degrees
	
		edgePoint : `numpy.ndarray`, list, tuple
			Two elements that describe a point on the circumference of the circle in the provided frame in degrees
	
		:param radius: float, `astropy.units.quantity.Quantity`
			The radius in degrees (if float) of the circle to be created.
		'''
        self._uncertainty = 4.848e-6  # defaults to 1 arcsec

        if ast_object:
            if any(
                [x is None for x in [frame, centerPoint, radius, edgePoint]]):
                raise Exception(
                    "ASTCircle: cannot specify both 'ast_object' and any other parameter."
                )

            if isinstance(ast_object, starlink.Ast.Circle):
                # make sure no other parameters are set
                self.astObject = ast_object
                return
            else:
                raise Exception(
                    "ASTCircle: The 'ast_object' provided was not of type starlink.Ast.Circle."
                )

        # check valid combination of parameters
        # -------------------------------------

        # make sure we have a frame we can work with
        if frame is None:
            raise Exception(
                "ASTCircle: A frame must be specified when creating an ASTCircle."
            )
        else:
            if isinstance(frame, ASTFrame):
                self.frame = frame
            elif isinstance(frame, starlink.Ast.Frame):
                self.frame = ASTFrame(frame=frame)
            else:
                raise Exception(
                    "ASTCircle: unexpected frame type specified ('{0}').".
                    format(type(frame)))

        if all([x is not None for x in [edge_point, radius]]):
            raise ValueError(
                "Both 'edge_point' and 'radius' cannot be simultaneously specified."
            )
        if center is None:
            raise ValueError("The 'center' parameter must be set.")
        if all([x is None for x in [edge_point, radius]]):
            raise ValueError(
                "Along with 'center', a 'radius' or 'edge_point' must be specified."
            )

        # input forms:
        #	CENTER_EDGE   (0) : circle specified by center point and any point on the circumference (p1 = [float,float], p2 = [float,float])
        #	CENTER_RADIUS (1) : circle specified by center point and radius                         (p1 = [float,float], p2 = float)
        input_form = None
        if edge_point is None:
            input_form = CENTER_RADIUS

        # convert np.array types to lists so that the value can be used in 'any' and 'all' comparisons.
#		if isinstance(centerPoint, np.ndarray):
# 			centerPoint = centerPoint.tolist()
# 		if isinstance(edgePoint, np.ndarray):
# 			edgePoint = edgePoint.tolist()
# 		if isinstance(centerPoint, astropy.coordinates.SkyCoord):
# 			centerPoint = [centerPoint.ra.to(u.deg).value, centerPoint.dec.to(u.deg).value]

# 		if all([centerPoint, edgePoint]) or all([centerPoint, radius]):
# 			if edgePoint:
# 				input_form = CENTER_EDGE
# 			else:
# 				input_form = CENTER_RADIUS
# 		else:
# 			raise Exception("ASTCircle: Either 'centerPoint' and 'edgePoint' OR 'centerPoint' " + \
# 							"and 'radius' must be specified when creating an ASTCircle.")

        if isinstance(center, astropy.coordinates.SkyCoord):
            p1 = [center.ra.to(u.rad).value, center.dec.to(u.rad).value]
        elif isinstance(center[0], astropy.units.quantity.Quantity):
            try:
                p1 = [center[0].to(u.rad).value, center[1].to(u.rad).value]
            except astropy.units.core.UnitConversionError as e:
                # todo: be more descriptive
                raise e
        else:
            p1 = [deg2rad(center[0]), deg2rad(center[1])]

        if input_form == CENTER_EDGE:
            # p1 = center point, p2 = edge point
            if isinstance(edge_point, astropy.coordinates.SkyCoord):
                p2 = [
                    edge_point.ra.to(u.rad).value,
                    edge_point.dec.to(u.rad).value
                ]
            else:
                p2 = [deg2rad(edge_point[0]), deg2rad(edge_point[1])]
        else:
            # p1 = center point, p2 = radius
            if isinstance(radius, astropy.units.quantity.Quantity):
                p2 = [radius.to(u.rad).value]
            else:
                p2 = [deg2rad(radius)]

        self.astObject = Ast.Circle(self.frame.astObject,
                                    input_form,
                                    p1,
                                    p2,
                                    unc=self.uncertainty)
Пример #7
0
# Get the Starlink specific defines.
defines = get_starlink_macros()

# Get the lists of source files for the NDF extra dependencies.
ndf_source_dep = []
for name_ in ['prm', 'ast', 'ary']:
    ndf_source_dep += get_source(name_)


hdsex_includedirs = ['include/', 'hds/', 'missingincludes/',
                     'hds_missingincludes/', 'hdf5/src/', 'hdf5/hl/src'] + \
    ['starutil', 'starmem/', 'cnf', 'ems', 'mers', 'chr', 'one'] + \
    [numpy.get_include()]


ndfex_includedirs = hdsex_includedirs + ['prm', 'ast', 'ary', 'ast_missingincludes/', Ast.get_include()]

# Can't build NDF without Ast!


# Define the two extensions.

hdsExtension = Extension('starlink.hds',
                         sources=['starlink/hds.pyx'],
                         include_dirs=hdsex_includedirs,
                         define_macros=defines,
                         libraries=['z'],
                         )


ndfExtension = Extension('starlink.ndf',
Пример #8
0
   def __init__(self,axes):
      if isinstance(axes,matplotlib.axes.Axes):
         self.axes = axes
         self.renderer = None

#  Save the current axis scales.
         self.Scales()

#  Create a temporary text string and line from which we can determine
#  the default graphics properties.
         xl,xr = self.axes.get_xlim()
         yb,yt = self.axes.get_ylim()
         xc = 0.5*(xl+xr);
         yc = 0.5*(yt+yb);
         text = matplotlib.text.Text( xc, yc, "a")
         line = matplotlib.lines.Line2D( [xc], [yc], marker="+")

#  Save the current default marker and text sizes.
         self.__deftsize = text.get_size()
         self.__defmsize = line.get_markersize()

#  Save the default text colour.
         defcol = text.get_color()

#  Save the default text font family and style.
         deffont = {"family":text.get_family(),"style":text.get_style()}

#  Save the default line style
         defstyle = line.get_linestyle()

#  A list used to convert AST integer marker types into matplotlib
#  character marker types.
         self.markers = ['s','.','+','*','o','x',',','^','v','<','>',
                         'p','h','D']

#  A list used to convert AST integer line style types into corresponding matplotlib
#  properties. Ensure the first line style is the default.
         self.styles = [ {"linestyle":defstyle}, {"linestyle":'-'},
                         {"linestyle":'--'}, {"linestyle":':'},
                         {"linestyle":'-.'} ]

#  A list used to convert AST integer font types into corresponding matplotlib
#  properties. Ensure the first font is the default.
         self.fonts = [ deffont, {"family":'serif',"style":'normal'},
                        {"family":'serif',"style":'italic'},
                        {"family":'sans-serif',"style":'normal'},
                        {"family":'sans-serif',"style":'italic'},
                        {"family":'monospace',"style":'normal'},
                        {"family":'monospace',"style":'italic'} ]

#  A list used to convert AST integer colours into corresponding matplotlib
#  properties. Ensure the first colour is the default.
         self.colours = [ {"color":defcol}, {"color":'#ff0000'}, {"color":'#00ff00'},
                          {"color":'#0000ff'}, {"color":'#00ffff'},
                          {"color":'#ff00ff'}, {"color":'#ffff00'},
                          {"color":'#000000'}, {"color":'#a9a9a9'},
                          {"color":'#808080'}, {"color":'#d3d3d3'},
                          {"color":'#ffffff'} ]

#  The current graphics attribute values as used by AST
         self.__attrs = { Ast.grfLINE:{Ast.grfSTYLE:1, Ast.grfWIDTH:1, Ast.grfSIZE:1,
                                       Ast.grfFONT:1, Ast.grfCOLOUR:1},
                          Ast.grfMARK:{Ast.grfSTYLE:1, Ast.grfWIDTH:1, Ast.grfSIZE:1,
                                       Ast.grfFONT:1, Ast.grfCOLOUR:1},
                          Ast.grfTEXT:{Ast.grfSTYLE:1, Ast.grfWIDTH:1, Ast.grfSIZE:1,
                                       Ast.grfFONT:1, Ast.grfCOLOUR:1}}

#  The corresponding graphics properties used by matplotlib
         self.__props = { Ast.grfLINE:{"solid_capstyle":'butt'},
                          Ast.grfMARK:{}, Ast.grfTEXT:{}}

#  Ensure the defaults are current.
         for attr in ( Ast.grfCOLOUR, Ast.grfWIDTH, Ast.grfSIZE,
                       Ast.grfFONT, Ast.grfSTYLE ):
            for prim in ( Ast.grfTEXT, Ast.grfLINE, Ast.grfMARK ):
               self.Attr( attr, 1.0, prim )

#  Set new delimiters for graphical sky axis values, using appropriate escape
#  sequences to get he superscripts looking nice.
         Ast.tunec( "hrdel", "%-%^85+%s70+h%>45+%+" )
         Ast.tunec( "mndel", "%-%^85+%s70+m%>45+%+" )
         Ast.tunec( "scdel", "%-%^85+%s70+s%>45+%+" )
         Ast.tunec( "dgdel", "%-%^90+%s60+o%>45+%+" )
         Ast.tunec( "amdel", "%-%^30+%s85+'%>45+%+" )
         Ast.tunec( "asdel", "%-%^30+%s85+\"%>45+%+" )
         Ast.tunec( "exdel", "10%-%^85+%s60+%>20+" )

#  Initialise the correction vector for text.
         self._xcorr = 0.0
         self._ycorr = 0.0

#  Save the current character heights, and update the vertical offset
#  correction for text.
         self.Qch()

#  Report an error if the supplied object is not suitable
      else:
         m = axes.__class__.__module__
         c = axes.__class__.__name__
         if m != "builtins":
            c = m + "." + c
         raise TypeError("The supplied axes object is a "+c+", it should "
                         "an instance of matplotlib.axes.Axes or a subclass")
Пример #9
0
	def __init__(self, ast_object:Ast.FitsChan=None, hdu:Union[astropy.io.fits.hdu.base.ExtensionHDU,fitsio.hdu.base.HDUBase]=None, header=None):
		'''
		Initialize object with either an HDU or header from fitsio or astropy.io.fits.
		
		Parameters
		----------
		header : astropy.io.fits.header.Header or fitsio.fitslib.FITSHDR or list of tuples/arrays (keyword,value)
		
		@param header FITS header as a dictionary of strings (keyword,value) or one of these types: astropy.io.fits.header.Header, fitsio.fitslib.FITSHDR, or a plain string divisible by 80 characters.
		'''
		self._frameSet = None

		if ast_object:
			if any([hdu, header]):
				raise ValueError("If 'ast_object' is provided, 'hdu' or 'header' should not be set.")
			else:
				if isinstance(ast_object, starlink.Ast.FitsChan):
					super().__init__(ast_object=ast_object)
				else:
					raise ValueError
		
		# ----------
		# Validation
		# ----------
		if all([hdu, header]):
			raise Exception("Only specify an HDU or header to create a ASTFITSChannel object.")
			
		# get header from HDU
		if hdu:
			if hdu and _astropy_available and isinstance(hdu, astropy.io.fits.hdu.base.ExtensionHDU):
				header = hdu.header        # type: astropy.io.fits.header.Header
			elif hdu and _fitsio_available and isinstance(hdu, fitsio.fitslib.HDUBase):
				header = hdu.read_header() # type: fitsio.fitslib.FITSHDR
			else:
				raise Exception("ASTFITSChannel: unknown HDU type specified ('{0}').".format(type(hdu)))
		# ----------
		
		self._dimensions = None
		self.astObject = Ast.FitsChan() # sink=self
		
		if header is not None:
			# Note that the starlink.Ast.Channel.read() operation is destructive.
			# Save the header so it can be restored/reused.
			self.header = header
			if isinstance(header, (astropy.io.fits.header.Header, fitsio.fitslib.FITSHDR)) or \
			   (isinstance(header, list) and isinstance(header[0], str)):
			   self._readHeader()
			elif isinstance(header, list):
				self._readHeader()
			elif isinstance(header, str) and (len(header) % 80 == 0):
				# split into list, then process
				self.header = [header[i:i+80] for i in range(0, len(header), 80)]
				self._readHeader()
			elif isinstance(header, dict):
				for keyword in header:
					self.astObject[keyword] = header[keyword]
					#self.addHeader(keyword=key, value=header[key])
				#self._readHeader()
			else:
				raise Exception("Could not work with the type of header provided ('{0}').".format(type(header)))
		else:
			pass # work with an empty Ast.FitsChan()
			logger.warning("ASTFITSChannel: no data found: working with an empty FITSChannel.")
Пример #10
0
import math
import starlink.Ast as Ast
import starlink.Atl as Atl

#  Open the FITS file using pyfits. A list of the HDUs in the FITS file is
#  returned.
hdu_list = pyfits.open( sys.argv[1] )

#  Create an object that will transfer FITS header cards between an AST
#  FitsChan and the PyFITS header describing the primary HDU of the
#  supplied FITS file.
adapter = Atl.PyFITSAdapter( hdu_list[ 0 ] )

#  Create a FitsChan and use the above adapter to copy all the header
#  cards into it.
fitschan = Ast.FitsChan( adapter, adapter )

#  Get the flavour of FITS-WCS used by the header cards currently in the
#  FitsChan. This is so that we can use the same flavour when we write
#  out the modified WCS.
encoding = fitschan.Encoding

#  Read WCS information from the FitsChan. Additionally, this removes all
#  WCS information from the FitsChan. The returned wcsinfo object
#  is an AST FrameSet, in which the current Frame describes WCS coordinates
#  and the base Frame describes pixel coodineates. The FrameSet includes a
#  Mapping that specifies the transformation between the two Frames.
wcsinfo = fitschan.read()

#  Check that the FITS header contained WCS in a form that can be
#  understood by AST.
Пример #11
0
	def __init__(self, circle_extent=None, figsize=(12.0, 12.0)):
		
		self.ast_plot = None # type: Ast.Plot
		
		# -------------------------------------------------------
		# Create frame set that will map the position in the plot
		# (i.e. pixel coordinates) to the sky (i.e. WCS)
		fits_chan = ASTFITSChannel()
		
		naxis1 = 100
		naxis2 = 100

		# The NAXIS values are arbitrary; this object is used for mapping.
		cards = {
			"CRVAL1":circle_extent.center[0], # reference point (image center) in sky coords
			"CRVAL2":circle_extent.center[1],
			"CTYPE1":"RA---TAN", #"GLON-TAN", # projection type
			"CTYPE2":"DEC--TAN", #"GLAT-TAN",
			"CRPIX1":50.5, # reference point (image center) point in pixel coords
			"CRPIX2":50.5,
			"CDELT1":2.1*circle_extent.radius/100,
			"CDELT2":2.1*circle_extent.radius/100,
			"NAXIS1":naxis1,
			"NAXIS2":naxis2,
			"NAXES":2,
		}
		naxis1 = cards['NAXIS1']
		naxis2 = cards['NAXIS2']
		pix2sky_mapping = ASTFrameSet.fromFITSHeader(fits_header=cards)
		# -------------------------------------------------------
		
		#  Create a matplotlib figure, 12x12 inches in size.
		dx = figsize[0] # 12.0
		dy = figsize[1] # 12.0
		fig = plt.figure( figsize=(dx,dy) )
		fig_aspect_ratio = dy/dx
		
		#  Set up the bounding box of the image in pixel coordinates, and get
		#  the aspect ratio of the image.
		bbox = (0.5, 0.5, naxis1 + 0.5, naxis2 + 0.5)
		fits_aspect_ratio = ( bbox[3] - bbox[1] )/( bbox[2] - bbox[0] )
		
		#  Set up the bounding box of the image as fractional offsets within the
		#  figure. The hx and hy variables hold the horizontal and vertical half
		#  widths of the image, as fractions of the width and height of the figure.
		#  Shrink the image area by a factor of 0.7 to leave room for annotated axes.
		if fig_aspect_ratio > fits_aspect_ratio :
		  hx = 0.5
		  hy = 0.5*fits_aspect_ratio/fig_aspect_ratio
		else:
		  hx = 0.5*fig_aspect_ratio/fits_aspect_ratio
		  hy = 0.5
		
		hx *= 0.7
		hy *= 0.7
		gbox = ( 0.5 - hx, 0.5 - hy, 0.5 + hx, 0.5 + hy )
		
		#  Add an Axes structure to the figure and display the image within it,
		#  scaled between data values zero and 100. Suppress the axes as we will
		#  be using AST to create axes.
		ax_image = fig.add_axes( [ gbox[0], gbox[1], gbox[2] - gbox[0],
								  gbox[3] - gbox[1] ], zorder=1 )
		ax_image.xaxis.set_visible( False )
		ax_image.yaxis.set_visible( False )
		#ax_image.imshow( hdu_list[0].data, vmin=0, vmax=200, cmap=plt.cm.gist_heat,
		#				origin='lower', aspect='auto')
		
		#  Add another Axes structure to the figure to hold the annotated axes
		#  produced by AST. It is displayed on top of the previous Axes
		#  structure. Make it transparent so that the image will show through.
		ax_plot = fig.add_axes( [ 0, 0, 1, 1 ], zorder=2 )
		ax_plot.xaxis.set_visible(False)
		ax_plot.yaxis.set_visible(False)
		ax_plot.patch.set_alpha(0.0)
		
		#  Create a drawing object that knows how to draw primitives (lines,
		#  marks and strings) into this second Axes structure.
		grf = Grf.grf_matplotlib( ax_plot )
		
		#print(f"gbox: {gbox}")
		#print(f"bbox: {bbox}")
		
		# box in graphics coordinates (area to draw on, dim of plot)
		#plot = Ast.Plot( frameset.astObject, gbox, bbox, grf )
		self.ast_plot = Ast.Plot( pix2sky_mapping.astObject, gbox, bbox, grf, options="Uni1=ddd:mm:ss" )
		 #, options="Grid=1" )
		#plot.set( "Colour(border)=2, Font(textlab)=3" );
		
		self.ast_plot.Grid = True # can change the line properties
		self.ast_plot.Format_1 = "dms"
		
		# colors:
		# 1 = black
		# 2 = red
		# 3 = lime
		# 4 = blue
		# 5 = 
		# 6 = pink
		
		self.ast_plot.grid()
		self.ast_plot.Width_Border = 2
		
	
		
Пример #12
0
    def __init__(self,
                 ast_object: starlink.Ast.Polygon = None,
                 frame: Union[ASTFrame, starlink.Ast.Frame] = None,
                 points=None,
                 fits_header=None):
        '''
		ASTPolygon is an ASTRegion that represents a polygon, a collection of vertices on a sphere in a 2D plane.

		Accepted signatures for creating an ASTPolygon:
		
		p = ASTPolygon(frame, points)
		p = ASTPolygon(fits_header, points)   # get the frame from the FITS header provided
		p = ASTPolygon(ast_object)            # where ast_object is a starlink.Ast.Polygon object

		Points may be provided as a list of coordinate points, e.g.
			[(x1, y1), (x2, y2), ... , (xn, yn)]
		or as two parallel arrays, e.g.
			[[x1, x2, x3, ..., xn], [y1, y2, y3, ..., yn]]
		
		:param ast_object: Create a new ASTPolygon from an existing :class:`starlink.Ast.Polygon` object.
		:param frame: The frame the provided points lie in, accepts either ASTFrame or starlink.Ast.Frame objects.
		:param points: Points (in degrees if frame is a SkyFrame) that describe the polygon, may be a list of pairs of points or two parallel arrays of axis points.
		:returns: Returns a new ASTPolygon object.
		'''

        if ast_object:
            if any([frame, points, fits_header]):
                raise ValueError(
                    "ASTPolygon: Cannot specify 'ast_object' along with any other parameter."
                )
            # test object
            if isinstance(ast_object, starlink.Ast.Polygon):
                super().__init__(ast_object=ast_object)
                return
            else:
                raise Exception(
                    "ASTPolygon: The 'ast_object' provided was not of type starlink.Ast.Polygon."
                )

        if points is None:
            raise Exception(
                "A list of points must be provided to create a polygon. This doesn't seem like an unreasonable request."
            )

        # Get the frame from the FITS header
        if fits_header:
            if frame is not None:
                raise ValueError(
                    "ASTPolygon: Provide the frame via the 'frame' parameter or the FITS header, but not both."
                )

            from ..channel import ASTFITSChannel
            frame_set = ASTFrameSet.fromFITSHeader(
                fits_header=fits_header
            ).baseFrame  # raises FrameNotFoundException

        if isinstance(frame, starlink.Ast.Frame):
            ast_frame = frame
        elif isinstance(frame, ASTFrame):
            ast_frame = frame.astObject
        else:
            raise Exception(
                "ASTPolygon: The supplied 'frame' object must either be a starlink.Ast.Frame or ASTFrame object."
            )

        if isinstance(frame, (starlink.Ast.SkyFrame, ASTSkyFrame)):
            points = np.deg2rad(points)

        # The problem with accepting both forms is that the case of two points is ambiguous:
        # [[x1,x2], [y1, y2]]
        # [(x1,y1), (x2, y2}]
        # I'm going to argue that two points does not a polygon make.
        if len(points) == 2 and len(points[0]) == 2:
            raise Exception(
                "There are only two points in this polygon, making the point ordering ambiguous. But is it really a polygon?"
            )

        # Internally, the starlink.Ast.Polygon constructor takes the parallel array form of points.
        # starlink.Ast.Polygon( ast_frame, points, unc=None, options=None )

        parallel_arrays = not (len(points[0]) == 2)

        if parallel_arrays:
            self.astObject = Ast.Polygon(ast_frame, points)
        else:
            if isinstance(points, np.ndarray):
                self.astObject = Ast.Polygon(ast_frame, points.T)
            else:
                # Could be a list or lists or tuples - reshape into parallel array form
                dim1 = np.zeros(len(points))
                dim2 = np.zeros(len(points))
                for idx, (x, y) in points:
                    dim1[idx] = x
                    dim2[idx] = y

                self.astObject = Ast.Polygon(ast_frame, np.array([dim1, dim2]))
Пример #13
0
    def fromPointsOnSkyFrame(radec_pairs: np.ndarray = None,
                             ra=None,
                             dec=None,
                             system: str = None,
                             skyframe: ASTSkyFrame = None,
                             expand_by=20 *
                             u.pix):  # astropy.coordinates.BaseRADecFrame
        '''
		Create an ASTPolygon from an array of points. NOTE: THIS IS SPECIFICALLY FOR SKY FRAMES.
		
		:param ra: list of RA points, must be in degrees (or :class:`astropy.units.Quantity` objects)
		:param dec: list of declination points, must be in degrees (or :class:`astropy.units.Quantity` objects)
		:param system: the coordinate system, see cornish.constants for accepted values
		:param frame: the frame the points lie in, specified as an ASTSkyFrame object
		:returns: new ASTPolygon object
		'''
        # author: David Berry
        #
        #  This method uses astConvex to find the shortest polygon enclosing a
        #  set of positions on the sky. The astConvex method determines the
        #  required polygon by examining an array of pixel values, so we first
        #  need to create a suitable pixel array. An (M,M) integer array is first
        #  created and initialised to hold zero at every pixel. A tangent plane
        #  projection is then determined that maps the smallest circle containing
        #  the specified (RA,Dec) positions onto the grid of (M,M) pixels. This
        #  projection is then used to convert each (RA,Dec) position into a pixel
        #  position and a value of 1 is poked into the array at each such pixel
        #  position. The astConvex method is then used to determine the shortest
        #  polygon that encloses all pixels that have value 1 in the array.
        #
        #  This polygon is then modified by moving each vertex 20 pixels radially
        #  away from the centre of the bounding disc used to define the extent of
        #  the pixel grid.
        #
        #  Finally, the resulting polygon is mapping from pixel coordinates to
        #  (RA,Dec).

        #  Set the required positional accuracy for the polygon vertices, given
        #  as an arc-distance in radians. The following value corresponds to 10
        #  arc-seconds. The size of the array (M) is selected to give pixels
        #  that have this size. Alternatively, specify a non-zero value for M
        #  explicitly, in which case the pixel size will be determined from M.
        ACC = 4.85E-5
        M = 0

        #  A SkyFrame describing the (RA,Dec) values.
        #skyfrm = Ast.SkyFrame( "System=FK5,Equinox=J2000,Epoch=1982.0" )

        #  The RA values (radians).
        # 		ra_list = [ 0.1646434, 0.1798973, 0.1925398, 0.2024329, 0.2053291,
        # 		            0.1796907, 0.1761278, 0.1701603, 0.1762123, 0.1689954,
        # 		            0.1725925, 0.1819018, 0.1865827, 0.19369, 0.1766037 ]
        #
        # 		#  The Dec values (radians).
        # 		dec_list = [ 0.6967545, 0.706133, 0.7176528, 0.729342, 0.740609,
        # 		             0.724532, 0.7318467, 0.7273944, 0.7225725, 0.7120513,
        # 		             0.7087136, 0.7211723, 0.7199059, 0.7268493, 0.7119532 ]

        # .. todo:: handle various input types (np.ndarray, Quantity)
        if isinstance(skyframe, (ASTSkyFrame, Ast.SkyFrame)):
            # if it's a sky frame of some kind, we will expect degrees
            ra = np.deg2rad(ra)
            dec = np.deg2rad(dec)

        ra_list = ra
        dec_list = dec

        # convert frame parameter to an Ast.Frame object
        if isinstance(skyframe, ASTFrame):
            skyframe = skyframe.astObject
        elif isinstance(skyframe, Ast.Frame):
            pass
        else:
            raise ValueError(
                f"The 'skyframe' parameter must be either an Ast.SkyFrame or ASTSkyFrame object; got {type(skyframe)}"
            )

        #  Create a PointList holding the (RA,Dec) positions.
        plist = Ast.PointList(skyframe, [ra_list, dec_list])

        #  Get the centre and radius of the circle that bounds the points (in
        #  radians).
        (centre, radius) = plist.getregiondisc()

        #  Determine the number of pixels (M) along each size of the grid that
        #  will produce pixels equal is size of ACC. If a non-zero value for M
        #  has already been set, use it.
        if M == 0:
            M = int(1 + 2.0 * radius / ACC)
        #logger.debug(f"Using grid size {M}")

        #  Create a minimal set of FITS-WCS headers that describe a TAN
        #  projection that projects the above circle into a square of M.M
        #  pixels. The reference point is the centre of the circle and is put
        #  at the centre of the square grid. Put the headers into a FitsChan.
        fc = Ast.FitsChan()
        fc["NAXIS1"] = M
        fc["NAXIS2"] = M
        fc["CRPIX1"] = 0.5 * (1 + M)
        fc["CRPIX2"] = 0.5 * (1 + M)
        fc["CRVAL1"] = centre[0] * Ast.DR2D
        fc["CRVAL2"] = centre[1] * Ast.DR2D
        fc["CDELT1"] = 2.0 * radius * Ast.DR2D / (M - 1)
        fc["CDELT2"] = 2.0 * radius * Ast.DR2D / (M - 1)
        fc["CTYPE1"] = 'RA---TAN'
        fc["CTYPE2"] = 'DEC--TAN'

        #  Re-wind the FitsChan and read the FrameSet corresponding to the above
        #  FITS headers.
        fc.clear("Card")
        wcs = fc.read()

        #  Use this FrameSet to transform all the (RA,Dec) positions into pixel
        #  coordinates within the grid.
        (x_list, y_list) = wcs.tran([ra_list, dec_list], False)

        #  Create an integer numpy array of the same shape, filled with zeros.
        ar = np.zeros(shape=(M, M), dtype=int)

        #  Poke a value 1 into the above array at each pixel position, checking
        #  each such position is inside the array.
        for (x, y) in zip(x_list, y_list):
            ix = int(round(x))
            iy = int(round(y))
            if ix >= 1 and ix <= M and iy >= 1 and iy <= M:
                ar[iy - 1, ix - 1] = 1

        #  Create a Polygon representing the convex hull that encloses the
        #  positions. This Polygon is defined in pixel coordinaates within the
        #  grid defined by the above FITS headers.
        pix_poly = Ast.convex(1, Ast.EQ, ar, [1, 1], [M, M], False)

        if expand_by.to_value(u.pix) > 0:
            #  Now expand the above polygon a bit. First get the vertex positions
            #  from the Polygon.
            (x_list, y_list) = pix_poly.getregionpoints()

            # Transform the centre position from sky to pixel coordinates.
            (x_cen, y_cen) = wcs.tran([[centre[0]], [centre[1]]], False)

            #  For each vertex, extend it's radial vector by 20 pixels. Create lists
            #  of extended x and y vertex positions. [Expanding about the centroid of
            #  the original vertices may give better results than expanding about the
            #  centre of the bounding disc in some cases].
            x_new = []
            y_new = []
            for (x, y) in zip(x_list, y_list):
                dx = x - x_cen[0]
                dy = y - y_cen[0]
                old_radius = math.sqrt(dx * dx + dy * dy)
                new_radius = old_radius + 20
                factor = new_radius / old_radius
                dx *= factor
                dy *= factor
                x_new.append(dx + x_cen[0])
                y_new.append(dy + y_cen[0])

            #  Create a new polygon in pixel coordinates using the extended vertex positions.
            big_poly = Ast.Polygon(wcs.getframe(Ast.BASE), [x_new, y_new])

            # Transform the Polygon into (RA,Dec).
            new_ast_polygon = big_poly.mapregion(wcs, skyframe)

        else:
            # Transform the Polygon into (RA,Dec)
            new_ast_polygon = pix_poly.mapregion(wcs, skyframe)

        return ASTPolygon(ast_object=new_ast_polygon)
Пример #14
0
def wcsalign(hdu_in, header, outname=None, clobber=False):
    """
    Align one FITS image to a specified header

    Requires pyast.

    Parameters
    ----------
    hdu_in : `~astropy.io.fits.PrimaryHDU`
        The HDU to reproject (must have header & data)
    header : `~astropy.io.fits.Header`
        The target header to project to
    outname : str (optional)
        The filename to write to.
    clobber : bool
        Overwrite the file ``outname`` if it exists

    Returns
    -------
    The reprojected fits.PrimaryHDU

    Credits
    -------
    Written by David Berry and adapted to functional form by Adam Ginsburg
    ([email protected])
    """
    import starlink.Ast as Ast
    import starlink.Atl as Atl
  
    #  Create objects that will transfer FITS header cards between an AST
    #  FitsChan and the fits header describing the primary HDU of the
    #  supplied FITS file.
    adapter_in = Atl.PyFITSAdapter(hdu_in)
    hdu_ref = pyfits.PrimaryHDU(header=header)
    adapter_ref = Atl.PyFITSAdapter(hdu_ref)
     
    #  Create a FitsChan for each and use the above adapters to copy all the header
    #  cards into it.
    fitschan_in = Ast.FitsChan(adapter_in, adapter_in)
    fitschan_ref = Ast.FitsChan(adapter_ref, adapter_ref)
     
    #  Get the flavour of FITS-WCS used by the header cards currently in the
    #  input FITS file. This is so that we can use the same flavour when we write
    #  out the modified WCS.
    encoding = fitschan_in.Encoding
     
    #  Read WCS information from the two FitsChans. Additionally, this removes
    #  all WCS information from each FitsChan. The returned wcsinfo object
    #  is an AST FrameSet, in which the current Frame describes WCS coordinates
    #  and the base Frame describes pixel coodineates. The FrameSet includes a
    #  Mapping that specifies the transformation between the two Frames.
    wcsinfo_in = fitschan_in.read()
    wcsinfo_ref = fitschan_ref.read()
     
    #  Check that the input FITS header contained WCS in a form that can be
    #  understood by AST.
    if wcsinfo_in is None:
        raise ValueError("Failed to read WCS information from {0}".format(hdu_in))
     
    #  This is restricted to 2D arrays, so check theinput  FITS file has 2 pixel
    #  axes (given by Nin) and 2 WCS axes (given by Nout).
    elif wcsinfo_in.Nin != 2 or wcsinfo_in.Nout != 2:
        raise ValueError("{0} is not 2-dimensional".format(hdu_in))
     
    #  Check the reference FITS file in the same way.
    elif wcsinfo_ref is None:
        raise ValueError("Failed to read WCS information from {0}".format(hdu_ref))
     
    elif wcsinfo_ref.Nin != 2 or wcsinfo_ref.Nout != 2:
        raise ValueError("{0} is not 2-dimensional".format(hdu_ref))
     
    #  Proceed if the WCS information was read OK.
 
    #  Attempt to get a mapping from pixel coords in the input FITS file to pixel
    #  coords in the reference fits file, with alignment occuring by preference in
    #  the current WCS frame. Since the pixel coordinate frame will be the base frame
    #  in each Frameset, we first invert the FrameSets. This is because the Convert method
    #  aligns current Frames, not base frames.
    wcsinfo_in.invert()
    wcsinfo_ref.invert()
    alignment_fs = wcsinfo_in.convert(wcsinfo_ref)

    #  Invert them again to put them back to their original state (i.e.
    #  base frame = pixel coords, and current Frame = WCS coords).
    wcsinfo_in.invert()
    wcsinfo_ref.invert()

    #  Check alignment was possible.
    if alignment_fs is None:
        raise Exception("Cannot find a common coordinate system shared by {0} and {1}".format(hdu_in,hdu_ref))
      
    else:
        #  Get the lower and upper bounds of the input image in pixel indices.
        #  All FITS arrays by definition have lower pixel bounds of [1,1] (unlike
        #  NDFs). Note, unlike fits AST uses FITS ordering for storing pixel axis
        #  values in an array (i.e. NAXIS1 first, NAXIS2 second, etc).
        lbnd_in = [1, 1]
        ubnd_in = [fitschan_in["NAXIS1"], fitschan_in["NAXIS2"]]
 
        #  Find the pixel bounds of the input image within the pixel coordinate
        #  system of the reference fits file.
        (lb1, ub1, xl, xu) = alignment_fs.mapbox(lbnd_in, ubnd_in, 1)
        (lb2, ub2, xl, xu) = alignment_fs.mapbox(lbnd_in, ubnd_in, 2)
 
        #  Calculate the bounds of the output image.
        lbnd_out = [int(lb1), int(lb2)]
        ubnd_out = [int(ub1), int(ub2)]
      
        #  Unlike NDFs, FITS images cannot have an arbitrary pixel origin so
        #  we need to ensure that the bottom left corner of the input image
        #  gets mapped to pixel [1,1] in the output. To do this we, extract the
        #  mapping from the alignment FrameSet and add on a ShiftMap (a mapping
        #  that just applies a shift to each axis).
        shift = [1 - lbnd_out[0],
                 1 - lbnd_out[1]]
      
        alignment_mapping = alignment_fs.getmapping()
        shiftmap = Ast.ShiftMap(shift)
        total_map = Ast.CmpMap(alignment_mapping, shiftmap)
      
        #  Modify the pixel bounds of the output image to take account of this
        #  shift of origin.
        lbnd_out[0] += shift[0]
        lbnd_out[1] += shift[1]
        ubnd_out[0] += shift[0]
        ubnd_out[1] += shift[1]
 
        #  Get the value used to represent missing pixel values
        if "BLANK" in fitschan_in:
            badval = fitschan_in["BLANK"]
            flags = Ast.USEBAD
        else:
            badval = 0
            flags = 0
 
        # Resample the data array using the above mapping.
        # total_map was pixmap; is this right?
        (npix, out, out_var) = total_map.resample(lbnd_in, ubnd_in,
                                                  hdu_in.data, None,
                                                  Ast.LINEAR, None, flags,
                                                  0.05, 1000, badval, lbnd_out,
                                                  ubnd_out, lbnd_out, ubnd_out)
 
        #  Store the aligned data in the primary HDU, and update the NAXISi keywords
        #  to hold the number of pixels along each edge of the rotated image.
        hdu_in.data = out
        fitschan_in["NAXIS1"] = ubnd_out[0] - lbnd_out[0] + 1
        fitschan_in["NAXIS2"] = ubnd_out[1] - lbnd_out[1] + 1

    #  The WCS to store in the output is the same as the reference WCS
    #  except for the extra shift of origin. So use the above shiftmap to
    #  remap the pixel coordinate frame in the reference WCS FrameSet. We
    #  can then use this FrameSet as the output FrameSet.
    wcsinfo_ref.remapframe(Ast.BASE, shiftmap)
 
    #  Attempt to write the modified WCS information to the primary HDU (i.e.
    #  convert the FrameSet to a set of FITS header cards stored in the
    #  FITS file). Indicate that we want to use original flavour of FITS-WCS.
    fitschan_in.Encoding = encoding
    fitschan_in.clear('Card')

    if fitschan_in.write(wcsinfo_ref) == 0:
        raise Exception("Failed to convert the aligned WCS to Fits-WCS")
 
    #  If successful, force the FitsChan to copy its contents into the
    #  fits header, then write the changed data and header to the output
    #  FITS file.
    else:
        fitschan_in.writefits()

    if outname is not None:
        hdu_in.writeto(outname, clobber=clobber)
    
    return hdu_in
Пример #15
0
# This script is featured on pyast issue page:
# https://github.com/timj/starlink-pyast/issues/8
# PyAst had been failing to write SIP files correctly, but they fixed this in
# v3.9.0.  We override their claim of success regardless, since they aren't
# necessarily accurate enough for our purposes (only accurate to 0.1 pixels).
# Thus, older PyAst versions work correctly in GalSim.

import starlink.Atl as Atl
import starlink.Ast as Ast
import astropy.io.fits as pyfits
import numpy

# http://fits.gsfc.nasa.gov/registry/sip/sipsample.fits
hdu = pyfits.open('sipsample.fits')[0]
fc = Ast.FitsChan(Atl.PyFITSAdapter(hdu))
wcs = fc.read()

# A random test position.  The "true" RA, Dec values are taken from ds9.
x = 242
y = 75
true_ra = (13 + 30 / 60. + 1.474154 / 3600. - 24.) * numpy.pi / 12.
true_dec = (47 + 12 / 60. + 51.794474 / 3600.) * numpy.pi / 180.

ra1, dec1 = wcs.tran(numpy.array([[x], [y]]))
print 'Initial read of sipsample.fits:'
print 'error in ra = ', (ra1 - true_ra) * 180. * 3600. / numpy.pi, 'arcsec'
print 'error in dec = ', (dec1 - true_dec) * 180. * 3600. / numpy.pi, 'arcsec'

# Now cycle through writing and reading to a file
Пример #16
0
# This script is featured on pyast issue page:
# https://github.com/timj/starlink-pyast/issues/8
# It also constructs the file tanflip.fits, which we use in the test suite.
# PyAst natively flips the order of RA and Dec when writing this file as a TAN WCS.
# This was a kind of input that wasn't otherwise featured in our test suite, but is
# apparently allowed by the fits standard.  So I added it.

import starlink.Atl as Atl
import starlink.Ast as Ast
import astropy.io.fits as pyfits
import numpy

# http://fits.gsfc.nasa.gov/registry/tpvwcs/tpv.fits
hdu = pyfits.open('tpv.fits')[0]
fc = Ast.FitsChan(Atl.PyFITSAdapter(hdu))
wcs = fc.read()

# A random test position.  The "true" RA, Dec values are taken from ds9.
'033009.340034', '-284350.811107', 418, 78, 2859.53882
x = 418
y = 78
true_ra = (3 + 30 / 60. + 9.340034 / 3600.) * numpy.pi / 12.
true_dec = -(28 + 43 / 60. + 50.811107 / 3600.) * numpy.pi / 180.

ra1, dec1 = wcs.tran(numpy.array([[x], [y]]))
print 'Initial read of tpv.fits:'
print 'error in ra = ', (ra1 - true_ra) * 180. * 3600. / numpy.pi, 'arcsec'
print 'error in dec = ', (dec1 - true_dec) * 180. * 3600. / numpy.pi, 'arcsec'

# Now cycle through writing and reading to a file
Пример #17
0
#!/usr/bin/env python

import numpy as np
import starlink.Ast as Ast

# Read in initial coordinates as J2000 coordinates
data_j2000 = np.radians(np.loadtxt('../initial_coords.txt'))
ra_j2000_fk5, dec_j2000_fk5 = data_j2000[:, 0], data_j2000[:, 1]

#  Create a Frame to describe J2000 FK5 coordinates, and another that
#  will be used in turn to describe each of the output coordinate systems.
#  Assume that the epoch of observation is J2000.0. The default values for
#  the reference equinox will be used (J2000.0 for FK5 and ecliptic, and
#  B1950.0 for FK4).
fk5_frame = Ast.SkyFrame(
    'System=FK5,Format(1)=hms.5,Format(2)=dms.5,Epoch=2000.0')
out_frame = Ast.SkyFrame('Format(1)=hms.5,Format(2)=dms.5,Epoch=2000.0')

#  Loop round each output coordinate system, modifying "out_frame" to
#  describe each one.
vals = {}
for system in 'FK4', 'Ecliptic', 'Galactic', 'ICRS':

    out_frame.System = system

    #  Get the transformation from FK5 J2000 to the current output system.
    fk5_to_out = fk5_frame.convert(out_frame)

    #  Transform the FK5 J2000 positions into the curent output system using
    #  the above transformation.
    vals[system] = fk5_to_out.tran([ra_j2000_fk5, dec_j2000_fk5])
Пример #18
0
ndf_source_dep = []
for name_ in ['prm', 'ast', 'ary']:
    ndf_source_dep += get_source(name_)



hdsex_includedirs = ['include/', 'hds/', 'missingincludes/',
                     'hds_missingincludes/', 'hdf5/src/', 'hdf5/hl/src'] + \
    ['starutil', 'starmem/', 'cnf', 'ems', 'mers', 'chr',\
     'one'] + \
    [numpy.get_include()]

from starlink import Ast
ndfex_includedirs = hdsex_includedirs + [
    'prm', 'ast', 'ary', 'ast_missingincludes/',
    Ast.get_include()
]

# Can't build NDF without Ast!

ndfex_includedirs.append(Ast.get_include())

# Define the two extensions.

hdsExtension = Extension(
    'starlink.hds',
    sources=[os.path.join('starlink', 'hds', 'hds.c')],
    include_dirs=hdsex_includedirs,
    define_macros=defines,
    libraries=['z'],
)
Пример #19
0
def rotate(infile, outfile, angle, xcen=None, ycen=None):
    #  Open the FITS file using pyfits. A list of the HDUs in the FITS file is
    #  returned.
    hdu_list = pyfits.open(infile)

    #  Create an object that will transfer FITS header cards between an AST
    #  FitsChan and the PyFITS header describing the primary HDU of the
    #  supplied FITS file.
    adapter = Atl.PyFITSAdapter(hdu_list[0])

    #  Create a FitsChan and use the above adapter to copy all the header
    #  cards into it.
    fitschan = Ast.FitsChan(adapter, adapter)

    #  Get the flavour of FITS-WCS used by the header cards currently in the
    #  FitsChan. This is so that we can use the same flavour when we write
    #  out the modified WCS.
    encoding = fitschan.Encoding

    #  Read WCS information from the FitsChan. Additionally, this removes all
    #  WCS information from the FitsChan. The returned wcsinfo object
    #  is an AST FrameSet, in which the current Frame describes WCS coordinates
    #  and the base Frame describes pixel coodineates. The FrameSet includes a
    #  Mapping that specifies the transformation between the two Frames.
    wcsinfo = fitschan.read()

    #  Check that the FITS header contained WCS in a form that can be
    #  understood by AST.
    if wcsinfo == None:
        print("Failed to read WCS information from {0}".format(infile))

    #  Rotation is restricted to 2D arrays, so check the FITS file has 2 pixel
    #  axes (given by Nin) and 2 WCS axes (given by Nout).
    elif wcsinfo.Nin != 2 or wcsinfo.Nout != 2:
        print("{0} is not 2-dimensional".format(infile))

    #  Proceed if the WCS information was read OK.
    else:

        #  Get the lower and upper bounds of the input image in pixel indices.
        #  All FITS arrays by definition have lower pixel bounds of [1,1] (unlike
        #  NDFs). Note, unlike pyfits AST uses FITS ordering for storing pixel axis
        #  values in an array (i.e. NAXIS1 first, NAXIS2 second, etc).
        lbnd_in = [1, 1]
        ubnd_in = [fitschan["NAXIS1"], fitschan["NAXIS2"]]

        #  Get the rotation angle and convert from degrees to radians.
        angle = float(angle) * Ast.DD2R

        #  Construct a MatrixMap that rotates by the required angle, converted to radians.
        sinang = math.sin(angle)
        cosang = math.cos(angle)
        pixmap = Ast.MatrixMap([[cosang, sinang], [-sinang, cosang]])

        #  If supplied, get the centre of rotation.
        if (xcen is not None) and (ycen is not None):
            #  Create aShiftMap to shift the origin and combine it with the
            #  MatrixMap, to give the desired centre of rotation (shift,
            #  rotate, then shift back again).
            shiftmap = Ast.ShiftMap([-xcen, -ycen])
            pixmap = Ast.CmpMap(shiftmap, pixmap)
            shiftmap.invert()
            pixmap = Ast.CmpMap(pixmap, shiftmap)

            # The dimensions of the output array are the same as the input array.
            lbnd_out = lbnd_in
            ubnd_out = ubnd_in

        #  If no centre of rotation was specified, we use the MatrixMap
        #  unchanged, and determine the bounds of the smallest output image that
        #  will hold the entire rotated input image. These are with respect to
        #  the pixel coordinates of the input array, and so some corners may have
        #  negative pixel coordinates.
        else:
            (lb1, ub1, xl, xu) = pixmap.mapbox(lbnd_in, ubnd_in, 1)
            (lb2, ub2, xl, xu) = pixmap.mapbox(lbnd_in, ubnd_in, 2)
            lbnd_out = [int(lb1), int(lb2)]
            ubnd_out = [int(ub1), int(ub2)]

        #  Get the value used to represent missing pixel values
        if "BLANK" in fitschan:
            badval = fitschan["BLANK"]
            flags = Ast.USEBAD
        else:
            badval = 0
            flags = 0

        # Resample the data array using the above mapping.
        (npix, out, out_var) = pixmap.resample(lbnd_in, ubnd_in,
                                               hdu_list[0].data, None,
                                               Ast.LINEAR, None, flags, 0.05,
                                               1000, badval, lbnd_out,
                                               ubnd_out, lbnd_out, ubnd_out)

        #  Store the rotated data in the HDU, and update the NAXISi keywords
        #  to hold the number of pixels along each edge of the rotated image.
        hdu_list[0].data = out
        fitschan["NAXIS1"] = ubnd_out[0] - lbnd_out[0] + 1
        fitschan["NAXIS2"] = ubnd_out[1] - lbnd_out[1] + 1

        #  Move the pixel origin of the output from "lbnd_out" to (1,1). Create a
        #  suitable ShiftMap, and append it to the total "old pixel coord" to
        #  "new pixel coords" mapping.
        shiftmap = Ast.ShiftMap([-lbnd_out[0], -lbnd_out[1]])
        pixmap = Ast.CmpMap(pixmap, shiftmap)

        #  Re-map the base Frame (i.e. the pixel coordinates Frame) so that it
        #  refers to the new data grid instead of the old one.
        wcsinfo.remapframe(Ast.BASE, pixmap)

        #  Attempt to write the modified WCS information to the primary HDU (i.e.
        #  convert the FrameSet to a set of FITS header cards stored in the
        #  FITS file). Indicate that we want to use original flavour of FITS-WCS.
        fitschan.Encoding = encoding
        fitschan.clear('Card')
        if fitschan.write(wcsinfo) == 0:
            print("Failed to convert the rotated WCS to Fits-WCS")

        #  If successfull, force the FitsCHan to copy its contents into the
        #  PyFITS header, then write the changed data and header to the output
        #  FITS file.
        else:
            fitschan.writefits()
            hdu_list.writeto(outfile, clobber=True, output_verify='ignore')
Пример #20
0
    def __init__(self, axes):
        if isinstance(axes, matplotlib.axes.Axes):
            self.axes = axes
            self.renderer = None

#  Save the current axis scales.
            self.Scales()

#  Create a temporary text string and line from which we can determine
#  the default graphics properties.
            xl, xr = self.axes.get_xlim()
            yb, yt = self.axes.get_ylim()
            xc = 0.5 * (xl + xr)
            yc = 0.5 * (yt + yb)
            text = matplotlib.text.Text(xc, yc, "a")
            line = matplotlib.lines.Line2D([xc], [yc], marker="+")

#  Save the current default marker and text sizes.
            self.__deftsize = text.get_size()
            self.__defmsize = line.get_markersize()

#  Save the default text colour.
            defcol = text.get_color()

#  Save the default text font family and style.
            deffont = {"family": text.get_family(), "style": text.get_style()}

#  Save the default line style
            defstyle = line.get_linestyle()

#  A list used to convert AST integer marker types into matplotlib
#  character marker types.
            self.markers = ['s', '.', '+', '*', 'o', 'x', ',', '^', 'v', '<', '>',
                            'p', 'h', 'D']

#  A list used to convert AST integer line style types into corresponding matplotlib
#  properties. Ensure the first line style is the default.
            self.styles = [{"linestyle": defstyle}, {"linestyle": '-'},
                           {"linestyle": '--'}, {"linestyle": ':'},
                           {"linestyle": '-.'}]

#  A list used to convert AST integer font types into corresponding matplotlib
#  properties. Ensure the first font is the default.
            self.fonts = [deffont, {"family": 'serif', "style": 'normal'},
                          {"family": 'serif', "style": 'italic'},
                          {"family": 'sans-serif', "style": 'normal'},
                          {"family": 'sans-serif', "style": 'italic'},
                          {"family": 'monospace', "style": 'normal'},
                          {"family": 'monospace', "style": 'italic'}]

#  A list used to convert AST integer colours into corresponding matplotlib
#  properties. Ensure the first colour is the default.
            self.colours = [{"color": defcol}, {"color": '#ff0000'}, {"color": '#00ff00'},
                            {"color": '#0000ff'}, {"color": '#00ffff'},
                            {"color": '#ff00ff'}, {"color": '#ffff00'},
                            {"color": '#000000'}, {"color": '#a9a9a9'},
                            {"color": '#808080'}, {"color": '#d3d3d3'},
                            {"color": '#ffffff'}]

#  The current graphics attribute values as used by AST
            self.__attrs = {Ast.grfLINE: {Ast.grfSTYLE: 1, Ast.grfWIDTH: 1, Ast.grfSIZE: 1,
                                          Ast.grfFONT: 1, Ast.grfCOLOUR: 1},
                            Ast.grfMARK: {Ast.grfSTYLE: 1, Ast.grfWIDTH: 1, Ast.grfSIZE: 1,
                                          Ast.grfFONT: 1, Ast.grfCOLOUR: 1},
                            Ast.grfTEXT: {Ast.grfSTYLE: 1, Ast.grfWIDTH: 1, Ast.grfSIZE: 1,
                                          Ast.grfFONT: 1, Ast.grfCOLOUR: 1}}

#  The corresponding graphics properties used by matplotlib
            self.__props = {Ast.grfLINE: {"solid_capstyle": 'butt'},
                            Ast.grfMARK: {}, Ast.grfTEXT: {}}

#  Ensure the defaults are current.
            for attr in (Ast.grfCOLOUR, Ast.grfWIDTH, Ast.grfSIZE,
                         Ast.grfFONT, Ast.grfSTYLE):
                for prim in (Ast.grfTEXT, Ast.grfLINE, Ast.grfMARK):
                    self.Attr(attr, 1.0, prim)

#  Set new delimiters for graphical sky axis values, using appropriate escape
#  sequences to get he superscripts looking nice.
            Ast.tunec("hrdel", "%-%^85+%s70+h%>45+%+")
            Ast.tunec("mndel", "%-%^85+%s70+m%>45+%+")
            Ast.tunec("scdel", "%-%^85+%s70+s%>45+%+")
            Ast.tunec("dgdel", "%-%^90+%s60+o%>45+%+")
            Ast.tunec("amdel", "%-%^30+%s85+'%>45+%+")
            Ast.tunec("asdel", "%-%^30+%s85+\"%>45+%+")
            Ast.tunec("exdel", "10%-%^85+%s60+%>20+")

#  Initialise the correction vector for text.
            self._xcorr = 0.0
            self._ycorr = 0.0

#  Save the current character heights, and update the vertical offset
#  correction for text.
            self.Qch()

#  Report an error if the supplied object is not suitable
        else:
            m = axes.__class__.__module__
            c = axes.__class__.__name__
            if m != "builtins":
                c = m + "." + c
            raise TypeError("The supplied axes object is a " + c + ", it should "
                            "an instance of matplotlib.axes.Axes or a subclass")
Пример #21
0
#!/usr/bin/python3
import starlink.Ast as Ast

bmask = open("bmask.log", "r")

lut = []
igood = -0.5
for i in range(32):
    for j in range(40):
        maskin = bmask.readline().rstrip()

        if maskin == "BAD":
            lut.append(Ast.BAD)
        else:
            igood += 1
            lut.append(igood)

bmask.close()

mapping = open("mapping.ast", "w")
mapping.write(
    str(
        Ast.CmpMap(Ast.UnitMap(1), Ast.LutMap(lut, 0.5, 1.0, "LutInterp=1"),
                   False)))
mapping.close()