def setup_class(cls): # We set up some representations with, on purpose, copy=False, # so we can check that broadcasting is handled correctly. lon = Longitude(np.arange(0, 24, 4), u.hourangle) lat = Latitude(np.arange(-90, 91, 30), u.deg) # With same-sized arrays cls.s0 = SphericalRepresentation( lon[:, np.newaxis] * np.ones(lat.shape), lat * np.ones(lon.shape)[:, np.newaxis], np.ones(lon.shape + lat.shape) * u.kpc, copy=False) cls.diff = SphericalDifferential( d_lon=np.ones(cls.s0.shape) * u.mas / u.yr, d_lat=np.ones(cls.s0.shape) * u.mas / u.yr, d_distance=np.ones(cls.s0.shape) * u.km / u.s, copy=False) cls.s0 = cls.s0.with_differentials(cls.diff) # With unequal arrays -> these will be broadcasted. cls.s1 = SphericalRepresentation(lon[:, np.newaxis], lat, 1. * u.kpc, differentials=cls.diff, copy=False) # For completeness on some tests, also a cartesian one cls.c0 = cls.s0.to_cartesian()
def test_cirs_to_hadec(): """ Check the basic CIRS<->HADec transforms. """ from astropy.coordinates import EarthLocation usph = golden_spiral_grid(200) dist = np.linspace(0.5, 1, len(usph)) * u.pc cirs = CIRS(usph, obstime='J2000') crepr = SphericalRepresentation(lon=usph.lon, lat=usph.lat, distance=dist) cirscart = CIRS(crepr, obstime=cirs.obstime, representation_type=CartesianRepresentation) loc = EarthLocation(lat=0 * u.deg, lon=0 * u.deg, height=0 * u.m) hadecframe = HADec(location=loc, obstime=Time('J2005')) cirs2 = cirs.transform_to(hadecframe).transform_to(cirs) cirs3 = cirscart.transform_to(hadecframe).transform_to(cirs) # check round-tripping assert_allclose(cirs.ra, cirs2.ra) assert_allclose(cirs.dec, cirs2.dec) assert_allclose(cirs.ra, cirs3.ra) assert_allclose(cirs.dec, cirs3.dec)
def __new__(cls, *args, **kwargs): origin_frame = kwargs.pop('north', None) if origin_frame is None: raise TypeError( "Can't initialize an NorthOffsetFrame without a `north` keyword." ) if hasattr(origin_frame, 'frame'): origin_frame = origin_frame.frame rep = origin_frame.spherical lon = rep.lon lat = rep.lat if lat > 0 * u.deg: lat = lat - 90 * u.deg rotation = None else: lon = lon - 180 * u.deg lat = -90 * u.deg - lat rotation = 180 * u.deg new_rep = SphericalRepresentation(lon=lon, lat=lat, distance=rep.distance) new_origin = origin_frame.realize_frame(new_rep) kwargs['origin'] = new_origin kwargs['rotation'] = rotation return SkyOffsetFrame(*args, **kwargs)
def test_cirs_to_altaz(): """ Check the basic CIRS<->AltAz transforms. More thorough checks implicitly happen in `test_iau_fullstack` """ from astropy.coordinates import EarthLocation ra, dec, dist = randomly_sample_sphere(200) cirs = CIRS(ra=ra, dec=dec, obstime='J2000') crepr = SphericalRepresentation(lon=ra, lat=dec, distance=dist) cirscart = CIRS(crepr, obstime=cirs.obstime, representation_type=CartesianRepresentation) loc = EarthLocation(lat=0 * u.deg, lon=0 * u.deg, height=0 * u.m) altazframe = AltAz(location=loc, obstime=Time('J2005')) cirs2 = cirs.transform_to(altazframe).transform_to(cirs) cirs3 = cirscart.transform_to(altazframe).transform_to(cirs) # check round-tripping assert_allclose(cirs.ra, cirs2.ra) assert_allclose(cirs.dec, cirs2.dec) assert_allclose(cirs.ra, cirs3.ra) assert_allclose(cirs.dec, cirs3.dec)
def test_regression_6236(): # sunpy changes its representation upon initialisation of a frame, # including via `realize_frame`. Ensure this works. class MyFrame(BaseCoordinateFrame): default_representation = CartesianRepresentation my_attr = QuantityAttribute(default=0, unit=u.m) class MySpecialFrame(MyFrame): def __init__(self, *args, **kwargs): _rep_kwarg = kwargs.get('representation_type', None) super().__init__(*args, **kwargs) if not _rep_kwarg: self.representation_type = self.default_representation self._data = self.data.represent_as(self.representation_type) rep1 = UnitSphericalRepresentation([0., 1] * u.deg, [2., 3.] * u.deg) rep2 = SphericalRepresentation([10., 11] * u.deg, [12., 13.] * u.deg, [14., 15.] * u.kpc) mf1 = MyFrame(rep1, my_attr=1. * u.km) mf2 = mf1.realize_frame(rep2) # Normally, data is stored as is, but the representation gets set to a # default, even if a different representation instance was passed in. # realize_frame should do the same. Just in case, check attrs are passed. assert mf1.data is rep1 assert mf2.data is rep2 assert mf1.representation_type is CartesianRepresentation assert mf2.representation_type is CartesianRepresentation assert mf2.my_attr == mf1.my_attr # It should be independent of whether I set the reprensentation explicitly mf3 = MyFrame(rep1, my_attr=1. * u.km, representation_type='unitspherical') mf4 = mf3.realize_frame(rep2) assert mf3.data is rep1 assert mf4.data is rep2 assert mf3.representation_type is UnitSphericalRepresentation assert mf4.representation_type is CartesianRepresentation assert mf4.my_attr == mf3.my_attr # This should be enough to help sunpy, but just to be sure, a test # even closer to what is done there, i.e., transform the representation. msf1 = MySpecialFrame(rep1, my_attr=1. * u.km) msf2 = msf1.realize_frame(rep2) assert msf1.data is not rep1 # Gets transformed to Cartesian. assert msf2.data is not rep2 assert type(msf1.data) is CartesianRepresentation assert type(msf2.data) is CartesianRepresentation assert msf1.representation_type is CartesianRepresentation assert msf2.representation_type is CartesianRepresentation assert msf2.my_attr == msf1.my_attr # And finally a test where the input is not transformed. msf3 = MySpecialFrame(rep1, my_attr=1. * u.km, representation_type='unitspherical') msf4 = msf3.realize_frame(rep2) assert msf3.data is rep1 assert msf4.data is not rep2 assert msf3.representation_type is UnitSphericalRepresentation assert msf4.representation_type is CartesianRepresentation assert msf4.my_attr == msf3.my_attr
def obsgeo_to_frame(obsgeo, obstime): """ Convert a WCS obsgeo property into an `~builtin_frames.ITRS` coordinate frame. Parameters ---------- obsgeo : array-like A shape ``(6, )`` array representing ``OBSGEO-[XYZ], OBSGEO-[BLH]`` as returned by ``WCS.wcs.obsgeo``. obstime : time-like The time assiociated with the coordinate, will be passed to `~.builtin_frames.ITRS` as the obstime keyword. Returns ------- `~.builtin_frames.ITRS` An `~.builtin_frames.ITRS` coordinate frame representing the coordinates. Notes ----- The obsgeo array as accessed on a `.WCS` object is a length 6 numpy array where the first three elements are the coordinate in a cartesian representation and the second 3 are the coordinate in a spherical representation. This function priorities reading the cartesian coordinates, and will only read the spherical coordinates if the cartesian coordinates are either all zero or any of the cartesian coordinates are non-finite. In the case where both the spherical and cartesian coordinates have some non-finite values the spherical coordinates will be returned with the non-finite values included. """ if (obsgeo is None or len(obsgeo) != 6 or np.all(np.array(obsgeo) == 0) or np.all(~np.isfinite(obsgeo))): # NOQA raise ValueError( f"Can not parse the 'obsgeo' location ({obsgeo}). " "obsgeo should be a length 6 non-zero, finite numpy array") # If the cartesian coords are zero or have NaNs in them use the spherical ones if np.all(obsgeo[:3] == 0) or np.any(~np.isfinite(obsgeo[:3])): data = SphericalRepresentation(*(obsgeo[3:] * (u.deg, u.deg, u.m))) # Otherwise we assume the cartesian ones are valid else: data = CartesianRepresentation(*obsgeo[:3] * u.m) return ITRS(data, obstime=obstime)
def test_atciqz_aticq(st): """Check replacements against erfa versions for consistency.""" t, pos = st jd1, jd2 = get_jd12(t, 'tdb') astrom, _ = erfa.apci13(jd1, jd2) ra, dec = pos srepr = SphericalRepresentation(ra, dec, 1) ra = ra.value dec = dec.value assert_allclose(erfa.atciqz(ra, dec, astrom), atciqz(srepr, astrom)) assert_allclose(erfa.aticq(ra, dec, astrom), aticq(srepr, astrom))
def make_earth_vis_grids(nside=32, n_reps=1): from acis_taco import calc_earth_vis, RAD_EARTH, acis_taco hp = astropy_healpix.HEALPix(nside=nside, order='nested') npix = astropy_healpix.nside_to_npix(nside) print(f'npix={npix}') lons, lats = hp.healpix_to_lonlat(np.arange(npix)) time0 = time.time() # Allow randomization between altitudes for i_rep in range(n_reps): vis_arrays = [] # Randomize the ray-trace points for each rep acis_taco._RANDOM_SALT = None acis_taco.SPHERE_XYZ = acis_taco.random_hemisphere(acis_taco.N_SPHERE) acis_taco.SPHERE_X = acis_taco.SPHERE_XYZ[:, 0].copy() for i_alt, alt in enumerate(alts): srs = SphericalRepresentation(lon=lons, lat=lats, distance=alt + RAD_EARTH) xyzs = srs.to_cartesian() peb_xs = xyzs.x.to_value() peb_ys = xyzs.y.to_value() peb_zs = xyzs.z.to_value() vis = [] for peb_x, peb_y, peb_z in zip(peb_xs, peb_ys, peb_zs): _, illums, _ = calc_earth_vis( p_earth_body=[peb_x, peb_y, peb_z]) vis.append(np.sum(illums)) vis = np.array(vis) vis_arrays.append(vis) vis_grid = np.vstack(vis_arrays) if i_alt % 10 == 0: print( f'alt={alt / 1000:.2f} km at dt={time.time() - time0:.1f}') ii = 1 while True: filename = Path(f'earth_vis_grid_nside{nside}_rep{ii}.npy') if filename.exists(): ii += 1 continue else: print(f'Saving {filename}') np.save(filename, vis_grid) break return vis_grid
def test_shape_setting(self): # Shape-setting should be on the object itself, since copying removes # zero-strides due to broadcasting. We reset the objects at the end. self.s0.shape = (2, 3, 7) assert self.s0.shape == (2, 3, 7) assert self.s0.lon.shape == (2, 3, 7) assert self.s0.lat.shape == (2, 3, 7) assert self.s0.distance.shape == (2, 3, 7) assert self.diff.shape == (2, 3, 7) assert self.diff.d_lon.shape == (2, 3, 7) assert self.diff.d_lat.shape == (2, 3, 7) assert self.diff.d_distance.shape == (2, 3, 7) # this works with the broadcasting. self.s1.shape = (2, 3, 7) assert self.s1.shape == (2, 3, 7) assert self.s1.lon.shape == (2, 3, 7) assert self.s1.lat.shape == (2, 3, 7) assert self.s1.distance.shape == (2, 3, 7) assert self.s1.distance.strides == (0, 0, 0) # but this one does not. oldshape = self.s1.shape with pytest.raises(ValueError): self.s1.shape = (1, ) with pytest.raises(AttributeError): self.s1.shape = (42, ) assert self.s1.shape == oldshape assert self.s1.lon.shape == oldshape assert self.s1.lat.shape == oldshape assert self.s1.distance.shape == oldshape # Finally, a more complicated one that checks that things get reset # properly if it is not the first component that fails. s2 = SphericalRepresentation(self.s1.lon.copy(), self.s1.lat, self.s1.distance, copy=False) assert 0 not in s2.lon.strides assert 0 in s2.lat.strides with pytest.raises(AttributeError): s2.shape = (42, ) assert s2.shape == oldshape assert s2.lon.shape == oldshape assert s2.lat.shape == oldshape assert s2.distance.shape == oldshape assert 0 not in s2.lon.strides assert 0 in s2.lat.strides self.setup()
def setup(self): lon = Longitude(np.arange(0, 24, 4), u.hourangle) lat = Latitude(np.arange(-90, 91, 30), u.deg) # With same-sized arrays self.s0 = SphericalRepresentation( lon[:, np.newaxis] * np.ones(lat.shape), lat * np.ones(lon.shape)[:, np.newaxis], np.ones(lon.shape + lat.shape) * u.kpc) self.diff = SphericalDifferential( d_lon=np.ones(self.s0.shape) * u.mas / u.yr, d_lat=np.ones(self.s0.shape) * u.mas / u.yr, d_distance=np.ones(self.s0.shape) * u.km / u.s) self.s0 = self.s0.with_differentials(self.diff) # With unequal arrays -> these will be broadcasted. self.s1 = SphericalRepresentation(lon[:, np.newaxis], lat, 1. * u.kpc, differentials=self.diff) # For completeness on some tests, also a cartesian one self.c0 = self.s0.to_cartesian()
def rotatedsun_to_reference(rotatedsun_coord, reference_frame): # Transform to HCI from_coord = rotatedsun_coord.base.realize_frame(rotatedsun_coord.data) hci_coord = from_coord.transform_to(HeliocentricInertial(obstime=reference_frame.obstime)) oldrepr = hci_coord.spherical # Rotate the coordinate in HCI from sunpy.physics.differential_rotation import diff_rot log.debug(f"Applying {rotatedsun_coord.duration} of solar rotation") newlon = oldrepr.lon + diff_rot(rotatedsun_coord.duration, oldrepr.lat, rot_type=rotatedsun_coord.rotation_model, frame_time='sidereal') newrepr = SphericalRepresentation(newlon, oldrepr.lat, oldrepr.distance) # Transform back from HCI hci_coord = HeliocentricInertial(newrepr, obstime=reference_frame.obstime) return hci_coord.transform_to(reference_frame)
def hadec_to_radec(ha, dec, t): """ Convert apparent HA, Dec to J2000 RA, Dec :param ha: hour angle with unit :param dec: declination with unit :param Time/str t: Observing time :return: SkyCoord object of J2000 coordinates """ # Convert time to Time object if given as string if isinstance(t, str): t = Time(t) # create spherical representation of ITRS coordinates of given ha, dec itrs_spherical = SphericalRepresentation(WSRT_LOC.lon - ha, dec, 1.) # create ITRS object, which requires cartesian input coord = SkyCoord(itrs_spherical.to_cartesian(), frame='itrs', obstime=t) # convert to J2000 return coord.icrs.ra, coord.icrs.dec
def hadec_to_radec(ha, dec, t, lon=WSRT_LOC.lat): """ Convert apparent HA, Dec to J2000 RA, Dec :param ha: hour angle with unit :param dec: declination with unit :param t: UT time (string or astropy.time.Time) :param lon: Longitude with unit (default: WSRT) :return: SkyCoord object of J2000 coordinates """ # Convert time to Time object if given as string if isinstance(t, str): t = Time(t) # create spherical representation of ITRS coordinates of given ha, dec itrs_spherical = SphericalRepresentation(lon - ha, dec, 1.) # create ITRS object, which requires cartesian input coord = SkyCoord(itrs_spherical.to_cartesian(), frame='itrs', obstime=t) # convert to J2000 return coord.icrs
def reference_to_rotatedsun(hgs_coord, rotatedsun_frame): int_frame = HeliographicStonyhurst( obstime=rotatedsun_frame.base.obstime) int_coord = hgs_coord.make_3d().transform_to( int_frame) # obstime change handled here oldrepr = int_coord.spherical # Rotate the coordinate in HGS from sunpy.physics.differential_rotation import diff_rot log.debug(f"Applying {rotatedsun_frame.duration} of solar rotation") newlon = oldrepr.lon - diff_rot( rotatedsun_frame.duration, oldrepr.lat, rot_type=rotatedsun_frame.rotation_model, frame_time='sidereal') newrepr = SphericalRepresentation(newlon, oldrepr.lat, oldrepr.distance) # Transform from HGS new_coord = int_coord.realize_frame(newrepr).transform_to( rotatedsun_frame.base) return rotatedsun_frame.realize_frame(new_coord.data)
0 * u.arcsec)], None), ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], None), ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], { 'obstime': '2011/01/01T00:00:00' })] """ These are common 3D params, kwargs are frame specific """ three_D_parameters = [ ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], None), ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], { 'obstime': '2011/01/01T00:00:00' }), ([0 * u.deg, 0 * u.arcsec, 1 * u.Mm], { 'representation': 'spherical' }), ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)], None), ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)], None), ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1 * u.Mm)], { 'obstime': '2011/01/01T00:00:00' }) ] # ============================================================================== # Helioprojective Tests # ============================================================================== @pytest.mark.parametrize('args, kwargs', two_D_parameters + [(None, { 'Tx': 0 * u.deg, 'Ty': 0 * u.arcsec
@pytest.mark.parametrize('frame', ['fk4', 'altaz']) def test_skycoord(frame): c = SkyCoord([[1, 2], [3, 4]], [[5, 6], [7, 8]], unit='deg', frame=frame, obstime=Time('2016-01-02'), location=EarthLocation(1000, 2000, 3000, unit=u.km)) cy = load(dump(c)) compare_coord(c, cy) @pytest.mark.parametrize('rep', [ CartesianRepresentation(1*u.m, 2.*u.m, 3.*u.m), SphericalRepresentation([[1, 2], [3, 4]]*u.deg, [[5, 6], [7, 8]]*u.deg, 10*u.pc), UnitSphericalRepresentation(0*u.deg, 10*u.deg), SphericalCosLatDifferential([[1.], [2.]]*u.mas/u.yr, [4., 5.]*u.mas/u.yr, [[[10]], [[20]]]*u.km/u.s), CartesianDifferential([10, 20, 30]*u.km/u.s), CartesianRepresentation( [1, 2, 3]*u.m, differentials=CartesianDifferential([10, 20, 30]*u.km/u.s)), SphericalRepresentation( [[1, 2], [3, 4]]*u.deg, [[5, 6], [7, 8]]*u.deg, 10*u.pc, differentials={ 's': SphericalDifferential([[0., 1.], [2., 3.]]*u.mas/u.yr, [[4., 5.], [6., 7.]]*u.mas/u.yr, 10*u.km/u.s)})])
# fix this. if attr == 'info.meta': if a1 is None: a1 = {} if a2 is None: a2 = {} assert np.all(a1 == a2) # Testing FITS table read/write with mixins. This is mostly # copied from ECSV mixin testing. el = EarthLocation(x=1 * u.km, y=3 * u.km, z=5 * u.km) el2 = EarthLocation(x=[1, 2] * u.km, y=[3, 4] * u.km, z=[5, 6] * u.km) sr = SphericalRepresentation([0, 1] * u.deg, [2, 3] * u.deg, 1 * u.kpc) cr = CartesianRepresentation([0, 1] * u.pc, [4, 5] * u.pc, [8, 6] * u.pc) sd = SphericalCosLatDifferential([0, 1] * u.mas / u.yr, [0, 1] * u.mas / u.yr, 10 * u.km / u.s) srd = SphericalRepresentation(sr, differentials=sd) sc = SkyCoord([1, 2], [3, 4], unit='deg,deg', frame='fk4', obstime='J1990.5') scc = sc.copy() scc.representation_type = 'cartesian' tm = Time([2450814.5, 2450815.5], format='jd', scale='tai', location=el) # NOTE: in the test below the name of the column "x" for the Quantity is # important since it tests the fix for #10215 (namespace clash, where "x" # clashes with "el2.x"). mixin_cols = { 'tm': tm,
def loc(self): sr = SphericalRepresentation(self.theta + self.phase0, self.inclination*np.cos(self.theta), self.r) return sr.to_cartesian() + self.parent_body.loc
# Licensed under a 3-clause BSD style license - see LICENSE.rst """Test replacements for ERFA functions atciqz and aticq.""" import pytest import erfa from astropy.tests.helper import assert_quantity_allclose as assert_allclose from astropy.time import Time import astropy.units as u from astropy.coordinates.builtin_frames.utils import get_jd12, atciqz, aticq from astropy.coordinates import SphericalRepresentation # Hard-coded random values sph = SphericalRepresentation(lon=[15., 214.] * u.deg, lat=[-12., 64.] * u.deg, distance=[1, 1.]) @pytest.mark.parametrize('t', [Time("2014-06-25T00:00"), Time(["2014-06-25T00:00", "2014-09-24"])]) @pytest.mark.parametrize('pos', [sph[0], sph]) def test_atciqz_aticq(t, pos): """Check replacements against erfa versions for consistency.""" jd1, jd2 = get_jd12(t, 'tdb') astrom, _ = erfa.apci13(jd1, jd2) ra = pos.lon.to_value(u.rad) dec = pos.lat.to_value(u.rad) assert_allclose(erfa.atciqz(ra, dec, astrom), atciqz(pos, astrom)) assert_allclose(erfa.aticq(ra, dec, astrom), aticq(pos, astrom))
def plot_star(self, fade_out=True): spots_spherical = SphericalRepresentation( self.phi * u.rad, (self.theta - np.pi / 2) * u.rad, 1 * R_sun) self.spots_spherical = spots_spherical fig, ax = plot_star(spots_spherical, fade_out=fade_out)
def plot_star(spots_spherical, fade_out=False): """ Parameters ---------- spots_spherical : `~astropy.coordinates.SphericalRepresentation` Points in spherical coordinates that represent the positions of the star spots. """ oldrcparams = matplotlib.rcParams matplotlib.rcParams['font.size'] = 18 fig, ax = plt.subplots(2, 3, figsize=(16, 16)) positive_x = ax[0, 0] negative_x = ax[1, 0] positive_y = ax[0, 1] negative_y = ax[1, 1] positive_z = ax[0, 2] negative_z = ax[1, 2] axes = [ positive_z, positive_x, negative_z, negative_x, positive_y, negative_y ] axes_labels = ['+z', '+x', '-z', '-x', '+y', '-y'] # Set black background plot_props = dict(xlim=(-1, 1), ylim=(-1, 1), xticks=(), yticks=()) drange = np.linspace(-1, 1, 100) y = np.sqrt(1 - drange**2) bg_color = 'k' for axis in axes: axis.set(xticks=(), yticks=()) axis.fill_between(drange, y, 1, color=bg_color) axis.fill_between(drange, -1, -y, color=bg_color) axis.set(**plot_props) axis.set_aspect('equal') # Set labels positive_x.set(xlabel='$\hat{z}$', ylabel='$\hat{y}$') # title='+x', positive_x.xaxis.set_label_position("top") positive_x.yaxis.set_label_position("right") negative_x.set(xlabel='$\hat{z}$', ylabel='$\hat{y}$') # title='-x', negative_x.xaxis.set_label_position("top") positive_y.set(xlabel='$\hat{z}$', ylabel='$\hat{x}$') positive_y.xaxis.set_label_position("top") negative_y.set(xlabel='$\hat{z}$', ylabel='$\hat{x}$') negative_y.xaxis.set_label_position("top") negative_y.yaxis.set_label_position("right") negative_z.set(xlabel='$\hat{y}$', ylabel='$\hat{x}$') # title='-z', negative_z.yaxis.set_label_position("right") positive_z.set(xlabel='$\hat{y}$', ylabel='$\hat{x}$') # title='+z', positive_z.yaxis.set_label_position("right") positive_z.xaxis.set_label_position("top") for axis, label in zip(axes, axes_labels): axis.annotate(label, (-0.9, 0.9), color='w', fontsize=14, ha='center', va='center') # Plot gridlines n_gridlines = 9 print("theta grid spacing: {0} deg".format(180. / (n_gridlines - 1))) n_points = 35 pi = np.pi thetaitude_lines = SphericalRepresentation( np.linspace(0, 2 * pi, n_points)[:, np.newaxis] * u.rad, np.linspace(-pi / 2, pi / 2, n_gridlines).T * u.rad, np.ones((n_points, 1))).to_cartesian() phigitude_lines = SphericalRepresentation( np.linspace(0, 2 * pi, n_gridlines)[:, np.newaxis] * u.rad, np.linspace(-pi / 2, pi / 2, n_points).T * u.rad, np.ones((n_gridlines, 1))).to_cartesian() for i in range(thetaitude_lines.shape[1]): for axis in [positive_z, negative_z]: axis.plot(thetaitude_lines.x[:, i], thetaitude_lines.y[:, i], ls=':', color='silver') for axis in [positive_x, negative_x, positive_y, negative_y]: axis.plot(thetaitude_lines.y[:, i], thetaitude_lines.z[:, i], ls=':', color='silver') for i in range(phigitude_lines.shape[0]): for axis in [positive_z, negative_z]: axis.plot(phigitude_lines.y[i, :], phigitude_lines.x[i, :], ls=':', color='silver') for axis in [positive_x, negative_x, positive_y, negative_y]: axis.plot(phigitude_lines.y[i, :], phigitude_lines.z[i, :], ls=':', color='silver') # Plot spots spots_cart = spots_spherical.to_cartesian() spots_x = spots_cart.x / R_sun spots_y = spots_cart.y / R_sun spots_z = spots_cart.z / R_sun if fade_out: n = float(len(spots_x)) alpha_range = np.arange(n) alpha = (n - alpha_range) / n else: alpha = 0.5 for spot_ind in range(spots_x.shape[1]): above_x_plane = spots_x[:, spot_ind] > 0 above_y_plane = spots_y[:, spot_ind] > 0 above_z_plane = spots_z[:, spot_ind] > 0 below_x_plane = spots_x[:, spot_ind] < 0 below_y_plane = spots_y[:, spot_ind] < 0 below_z_plane = spots_z[:, spot_ind] < 0 positive_x.plot(spots_y[above_x_plane, spot_ind], spots_z[above_x_plane, spot_ind], '.', alpha=alpha) negative_x.plot(-spots_y[below_x_plane, spot_ind], spots_z[below_x_plane, spot_ind], '.', alpha=alpha) positive_y.plot(-spots_x[above_y_plane, spot_ind], spots_z[above_y_plane, spot_ind], '.', alpha=alpha) negative_y.plot(spots_x[below_y_plane, spot_ind], spots_z[below_y_plane, spot_ind], '.', alpha=alpha) positive_z.plot(spots_x[above_z_plane, spot_ind], spots_y[above_z_plane, spot_ind], '.', alpha=alpha) negative_z.plot(spots_x[below_z_plane, spot_ind], -spots_y[below_z_plane, spot_ind], '.', alpha=alpha) matplotlib.rcParams = oldrcparams return fig, ax