Plotting global contour data that crosses both the meridian and the dateline - python

So I have two different datasets. I have one that is a polar orbiting satellite that starts near the north pole goes down towards Africa then goes over the south pole and back up the Atlantic ocean. I also have a Global composite of a number of Geostationary satellites. That grid is a full global coverage from -90 to 90 latitude, and 0 to -0.2 (around the dateline) longitudes.
So when I plot my polar orbiting data. I get a funny striping across the northern hemisphere where the satellite crosses the dateline. Like this...
polar orbiting data
I did a search and found that if I do this to my longitude values
lons[lons < 0] += 360
that it then removes the strange striping. I think it actually just moves the stripes to the southern hemisphere (where is crosses the meridian), but since that area is all "missing" values it doesn't show on the plot, so I don't care.
polar orbiting data - longitudes all positive
So now there is the problem of the full Global dataset. When I plot it without converting all the longitudes to positive values, it has quite a few stripes going on. I believe it is every place there is rain that crosses the dateline.
Global dataset
When I try to apply the "fix" that worked for the polar data I get a really nasty very uninformative error.
IllegalArgumentException: Invalid number of points in LinearRing found 3 - must be 0 or >= 4
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
There is no traceback or anything, so I'm not even sure if it is matplotlib or cartopy or what that is throwing the error.
I've tried cropping the image by using set_extent() but it still has the stripes.
Any ideas how to fix this, or how to trick matplotlib/cartopy into plotting the data correctly?
Adding code, but not sure how much it will actually be of help. It is pretty basic. The issue is more with the fact that the rain data covers the full globe.
normal_proj = ccrs.PlateCarree(central_longitude=0)
pos_lons = lon_data.copy()
pos_lons[pos_lons < 0] += 360
cs = plt.contourf(pos_lons, lat_data, rr_data, clevs, cmap=cmap,
transform=normal_proj, norm=norm)

I think you're running into an annoying, but difficult to track down bug in CartoPy. Basically, in transforming the contours and clipping them to the map extent it generates some Shapely geometries incorrectly. Some things that have worked to get around the problem (not solve it) include slightly adjusting the map boundaries and adjusting the contour levels.

Related

Animated flight path plot in python

I would like to write a program for plotting an animated 3D ribbon image in python. The ribbon follows the flight path as provided by a log containing the following information:
Timestamp, pitch, roll, altitude, latitude, longitude, heading, turn rate.
The final figure should look something like this (without the aircraft figure).
Aircraft manoeuvres:
Please let me know how this can be done.
Edit:
Heading is the angle between the flight and the north direction. It is a scalar quantity measured in degrees.
Turn rate is rate of change of heading.
Pitch is up/down rotation and roll is rotation given by rolling over on either side. They are measured in degrees.
Below is a sample of the data:
Time: 801.475 alt (ft): 12599.88668 lat(deg): 63.94230675 lon(deg): -22.72656178 pitch(deg): 39.60080719 roll(deg): 40.49394608 heading(deg): 344.7094606 turnspeed: 8.104816363
These are all from the inertial frame of reference, which can also serve as axes for this plot.
Thank you
This is not a complete answer.
First, you need to convert your data to x,y,z coordinates.
let's say that you use feet, then you have to convert latitude and longitude to x,y.
It will not work if the plane moved a long distance, because the earth is not flat.
Your pitch, roll and heading data serves to calculate the (x,y,z) coordinates of the tips of the wings (or the border of the ribbon) relative to the (x,y,z) of the center of the plane.
You need quaternions or geometric algebra to do that. You can also do it with basic trigonometry, but you risk gimbal lock bugs.
Then you need to interpolate your data, for the timestep you choose.
With your interpolated data, you get 2 arrays of (x,y,z) for each ribbon border, which you can plot as lines in 3D.
To do the plot you need to choose a position of the viewer, and a direction to which he is looking at.
If you want to do an animation, you use the same data, but google how to do animations after you managed to do the interpolations.
When the position of the plane at the time t, t+1 is
position[t] =[x,y,z]
position[t+1]=[x1,y1,z1]
the direction at which the plane is moving is
velocity[t+1/2]=position[t+1]-position[t]=[x1-x,y1-y,z1-z]/(t+1/2-t)
From the Position[t], you have to calculate the position of the right wing tip WR[t], and left wing tip WL[t], which are the [x,y,z] coordinates of the ribbons at the time t
Now, following this convention from Wikipedia
If we conjecture that the viewer is looking at the North, X is positive towards East, Y is positive towards the North, and Z is positive away from the center of earth (That depends on how did you converted latitude/longitude to x,y)
-If the length of a wing is L, then the coordinate of the rigth wing tip, relative to the center of the plane Position[t], would be [L,0,0], when the plane is leveled, aiming at the North.
At the time t the right wing tip WR[t] shold be at coordinates:
WR[t] = Position[t] + RotateVectorByRoll(RotateVectorByPitch(RotateVectorByHeading([L,0,0], Θh), ΘP), ΘR)

How make a correct gradient map using Numpy.gradient

I made use of numpy.gradient to calculate the gradient map of a scalar-field map. I guess I have not known numpy.gradient very well so that I might produce an incorrect gradient map. I post my code and the resulting map below:
from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np
subhdu = fits.open('test_subim.fits')[0]
subhdu = subhdu.data
fig = plt.figure(1, figsize = (30,30))
ax = fig.add_axes([0.1,0.7,0.5,0.2])
xr = np.arange(0, subhdu.shape[1], 1)
yr = np.arange(0, subhdu.shape[0], 1)
xx, yy = np.meshgrid(xr,yr)
dx, dy = np.gradient(subhdu.astype('float'))
im = ax.imshow(subhdu,origin='lower',cmap='bwr')
ax.quiver(xx,yy,dx,dy,scale=5,angles="uv",headwidth = 5)
fig.colorbar(im,pad=0)
ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
I am confused with two things about my resulting map:
Why the gradients in the masked area do not point toward as the green arrows;
Why the edges of the map do not have the gradient calculation?
I would appreciate if anyone can help me figure out my confusions. If you want to play with my data 'test_subim.fits', please visit my google drive. Before playing it, you must install the package astropy probably through the following command, pip install astropy.
Thank you very much again in advance for anyone who can help me out.
1) Because the 'white part' is not the top of the mountain, it goes, blue -> white -> red, as you can see in the bar in the right hand side. So the blue is the valley and the red are the mountains, and the arrows point where it is uphill.
2) The edges of the map don't have a gradient calculation because the gradient is calculated with respect to it's full neighbourhood. A gradient is a measure of how much the surface is changing with respect to everything around it, i.e it points towards the steepest ascent with respect to the entire neighbourhoud. If some of the everything around it is missing, like at the edges, you can't calculate it.
More mathematically, your function at the edges is not differentiable, so you can't compute a gradient.
EDIT: Let's go more in depth:
The gradient is not just the difference between two points. It is a measure for how much the surface is at that space locally. Let's take a look at a five by five example. We will calculate the gradient for the middle point. It points in the steepest direction, the direction in which if you were walking on a hill, would get you up the highest by only taking one step. How do you know this direction, you look at all the directions - let's say 1°, 2°, .. 360° - (I'm cutting some mathematical corners here but that's not important right now), take a step, see how much height you have won, and then you go back to the starting position. The direction that got you to the highest point is the direction of the gradient. How much height you have won is given by the size of the gradient (how long the arrow is).
Now let's say you are standing at the top (which is the top left pixel in a 2D view), and you want to take a step in each direction. Down left, no problem, down right, no problem, but up right and up left? There's no pixel there??? What do I do now? That's why there is no gradient.
Lets say we change the terrain from the left image to the terrain in the right image. Then the gradient will point in a direction between the - now two - heighest pixels.

Plotting Error Bars As Gradients

I have a series of observations for risk and performance (x, y co-ordinates). These are based on a series of bootstrap samples. I also have the 5th and 95th percentiles of the bootstrap samples - these represent the 90% probability window around the observations.
As it stands I am plotting this data as a scatter, then using error bars to show the probability window around the observation. Note the error bars are not symmetrical on either axis.
I'd like to instead plot these as an ellipse around the center point, ideally with a gradient going from an alpha of 1 at the center to ~0.2 at the edge.
Could anyone give me a nudge in the correct direction for this? Equally if anyone has a more elegant way to demonstrate a probability window around points on a scatter I'm happy to try it.

How to plot an orbit with pyephem/matplotlib

With pyephem I can take orbital elements from the Minor Planet Center and add them into a ephem.EllipticalBody().
To plot the orbit I've been getting the computing the sun distance, heliocentric latitiude and longitude over a the period of the orbit and plotting that:
dt = body._epoch
period = (sqrt(a**3))
timespace = np.linspace(dt-((period*365)/2),
dt+((period*365)/2), 720)
theta_e = []
r_e = []
phi_e = []
for t in timespace:
body.compute(t)
theta_e.append(body.hlon)
phi_e.append(body.hlat)
r_e.append(body.sun_distance)
subplot = figure(figsize=(20, 20)).add_subplot(111, polar=True)
subplot.scatter(theta_e, r_e*cos(phi_e), s=0.5)
This approch works ok for minor planets that have short periods (a few years). However when I go to the extreme and plot say Sedna I get:
http://i.stack.imgur.com/wxRCW.png
So it looks as though pyephem is being clever and taking apsidal precession into account. Which isn't something I need for this.
Any suggestions so on how I can plot the orbit from the orbital elements or what I'm doing wrong here? Ideally I'll like to be able to do plots from different 'views' to show the inclination as well as eccentricity or perhaps a live mayavi scene.
I suspect that the phenomenon here is not apsidal precession, because the libastro library beneath PyEphem uses simple Keplerian orbits when given elliptical coordinates.
Instead, my guess is that you are seeing the Earth’s polar precession, which is moving the heliocentric latitude and longitude system out from under you as you are trying to plot. For most objects the effect is negligible, but an 11,000-year orbit is enough time for the Earth’s pole to make it a good bit of the way around the sky.
The only coordinates that libastro produces that are likely to be immune to the effect (assuming that a compute(…, epoch=J2000) does not make the heliocentric longitude stable?) are the a_ra and a_dec coordinates, so you might have to pull those for both the Sun and Sedna, convert them into vectors, and subtract.

Difficulties with RA/Dec and Alt/Azi conversions with pyEphem

I'm trying to go from alt/azi to RA/Dec for a point on the sky at a fixed location, trying out pyEphem. I've tried a couple of different ways, and I get sort of the right answer, within a couple of degrees, but I'm expecting better, and I can't figure out where the problems lie.
I've been using Canopus as a test case (I'm not after stars specifically, so I can't use the in-built catalogue). So in my case, I know that at
stn = ephem.Observer()
# yalgoo station, wa
stn.long = '116.6806'
stn.lat = '-28.3403'
stn.elevation = 328.0
stn.pressure = 0 # no refraction correction.
stn.epoch = ephem.J2000
stn.date = '2014/12/15 14:32:09' #UTC
Stellarium, checked with other web sites tell me Canopus should be at
azi, alt '138:53:5.1', '56:09:52.6' or in equatorial RA 6h 23m 57.09s/ Dec. -52deg 41' 44.6"
but trying:
cano = ephem.FixedBody()
cano._ra = '6:23:57.1'
cano._dec = '-52:41:44.0'
cano._epoch = ephem.J2000
cano.compute( stn)
print( cano.az, cano.alt)
>>>(53:22:44.0, 142:08:03.0)
about 3 degrees out. I've also tried the reverse,
ra, dec = stn.radec_of('138:53:5.1', '56:09:52.6')
>>>(6:13:18.52, -49:46:09.5)
where I'm expecting 6:23 not 6:13. Turning on refraction correction makes a small difference, but not enough, and I've always understood aberration and nutation were much smaller effects than this offset as well?
As a follow up, I've tried manual calculations, based on 'Practical Astronomy with your calculator'; so for dec:
LAT = math.radians(-28.340335)
LON = math.radians(116.680621667)
ALT = math.radians(56.16461)
AZ = math.radians(138.88475)
sinDEC = (math.sin( LAT)*math.sin( ALT)
+ math.cos( LAT)*math.cos( ALT)*math.cos( AZ) )
DEC = math.asin( sinDEC)
DEC_deg = math.degrees(DEC)
print( 'dec = ', DEC_deg )
>>>('dec = ', -49.776032754148986)
again, quite different from '56:09:52.6', but reasonably close to pyEphem - so now I'm thoroughly confused! So now I'm suspecting the problem is my understanding, rather than pyEphem - could someone enlighten me about the correct way to go do RADEC/ALTAZI conversions, and why things are not lining up?!
First some notes
Atmospheric scattering and relative speed between observer and object
have the maximal error (near horizon) up to 0.6 degree which is nowhere near your error.
how can altitude be over 90 degrees?
you got swapped data for azimut and altitude
I put your observer data into mine program and result was similar to yours
but I visually search for that star instead of putting the coordinates. Result was also about 3-4 degrees off in RA axis
RA=6.4h Dec=-52.6deg
azi=142.4deg alt=53.9deg
mine engine is in C++, using Kepler's equation
Now what can be wrong:
mine stellar catalog can be wrongly converted
rotated wrongly with some margin but strongly doubt that it is 3 degrees. Also perspective transforms can add some error while rendering at 750AU distance from observer. I never tested for Southern sky (not visible from mine place).
we are using different Earth reference frame then the data you comparing to
I found out that some sites like NASA Horizon use different reference frame which does not correspond with mine observations. Look here
calculate the time when the sun is X degrees below/above the Horizon
at the start of the answer is link to 2 sites with different reference frames when you compare the result they are off. The second link is corresponding with mine observations the rest is dealing (included source code) with Kepler's equation based Solar system simulation. The other sublinks are also worth looking into.
I could have a bug in mine simulation/data
I have referenced data to this engine which could partially hide any computation errors from mine observer position so handle all above text with taken that it mind.
you could use wrong time/Julian date to stellar time conversions
if your time is off then the angles will not match...
How to resolve this?
pick up your Telescope, set up equatoreal coordinate system/mount to it and measure Ra/Dec Azi/Alt for known (distant) object in reality and compare with computed positions. Only this way you can decide which value is good or wrong (for reference frame you are using). Do this on star not planet !!! Do this on high altitude angles not near Horizon !!!
How to transform between azimutal and equatoreal coordinates
I compute transform matrix Eath representing earth's coordinate system (upper right) in heliocentric coordinate system as global coordinate system (left) then I compute another matrix NEH representing observer on Earth's surface (North,East,High/Altitude ... lower right).
After this it is just a matter of matrix and vector multiplications and conversion between Cartesian and spherical coordinate systems look here:
Representing Points on a Circular Radar Math approach
for more insight to azimutal coordinates. if you use just that simple equation like in your example then you do not account for many things... The Earth position is computed by Kepler's equation, rotation is given by daily rotation, nutation and precession included.
I use 64 bit floating point values which can create round errors but not that high ...
I use geometric North Pole as observer reference (this could add some serious error near poles).
The biggest thing that can affect this is the speed of light but that account for near earth 'moving' objects like planets not stars (except Sun) because their computed position is visible after some time ... For example Sun-Earth distance is about 8 light minutes so we see the Sun where it was 8 minutes ago. If the effemerides data is geometrical only (not account for this) then this can lead to high errors if not computed properly.
Newer effemerides models use gravity integration instead of Kepler so their data must be geometrical and the final output is then corrected by the time shift ...

Categories