Pyephem, define and plotting stars for different epochs - python

I'm trying to make a program that displays stars of my choice, from different locations on Earth and at different epochs. I've got it working so that I can display objects from ephem's database, such as Venus, but the stars I want to display aren't in the catalogue. How would I define the stars in Capricornus so they read to the program like any other star?
I've researched around and found articles similar to what I want:
The list of stars available:
https://github.com/brandon-rhodes/pyephem/blob/master/ephem/stars.py
Sample script plotting Big Dipper:http://nbviewer.ipython.org/github/brandon-rhodes/pyephem/blob/master/issues/github-issue-61.ipynb#
The code I'm using to generate observation site and desired objects:
#Define observer location
gatech = Observer()
gatech.lon = '-3.0' #Longitude positive in the East
gatech.lat = '+51.0' #Latitude positive in the North
gatech.elevation = 0
#Set date of observation and then prints Altitude and Azimuth of object
gatech.date = ((2000, 1, 1, 9, 30, 0)) #Year,month,day,hour,minute,second
v1 = Venus(gatech)
v1altrad = ('%.12f' % float(v1.alt))
v1azrad = ('%.12f' % float(v1.az -3.14159))
And inputting this into a matplotlib function produces the correct image.
As far as I know, I just need to figure out how to define the stars I want to see, as everything else appears to work. Any help plotting the stars of Capricorn would be greatly appreciated.

What you really want to do is to convert arbitrary equatorial coordinates to horizontal coordinates for a given location and time.
There are at least two options:
You can either create your own version of "stars.py", say "mystars.py" and
import that,
or do something like this
star = ephem.FixedBody(ra='21:00:00', dec='-20:00:00')
star.compute(gatech)
print(star.alt, star.az)

Related

Closing holes in mesh while retaining point cloud shape

I have a ply file that I am attempting to turn into a mesh for the purposes of ray tracing. It looks like this is the open3d visualizer and is supposed to represent a part of a city:
I used open3d to get make the following mesh as following(kdtree is just to get small number of points as file is huge):
input_file = "san.ply"
pcd = o3d.io.read_point_cloud(input_file)
point_cloud_in_numpy = np.asarray(pcd.points)
color = np.asarray(pcd.colors)
kd = scipy.spatial.cKDTree(point_cloud_in_numpy) #create kdtree for fast querying
near = kd.query_ball_point([0, 0, 0], 100)
items = point_cloud_in_numpy[near]
colors = color[near]
pcd2 = o3d.geometry.PointCloud()
pcd2.colors = o3d.utility.Vector3dVector(colors)
pcd2.points = o3d.utility.Vector3dVector(items)
pcd2.estimate_normals()
distances = pcd2.compute_nearest_neighbor_distance()
avg_dist = np.mean(distances)
radius = 2 * avg_dist
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
pcd2,
o3d.utility.DoubleVector([radius, radius * 2]))
vertices = np.asarray(mesh.vertices)
faces = np.asarray(mesh.triangles)
o3d.visualization.draw_geometries([mesh])
However, when graphing the mesh, we get something that looks like this:
Many holes and just not at all optimal for ray tracing. I also tried using the create_from_point_cloud_poisson method instead however I kept on getting the following error:
[ERROR] /Users/yixing/repo/Open3D/build/poisson/src/ext_poisson/PoissonRecon/Src/FEMTree.IsoSurface.specialized.inl (Line 1463)
operator()
Failed to close loop [6: 87 64 18] | (113981): (2752,2560,2196)
which I found no way to fix online. I tried looking around but the best I found was pymeshfix which doesn't even work because "The input is assumed to represent a single closed solid object", which my point cloud is obviously not. I'm just looking for a good way to perform surface reconstruction that lets me keep the shape of the city while also fixing all the holes and making all surfaces created by points near eachother surfaces watertight.
Maybe you can close the holes with fill_holes() from the tensor-based TriangleMesh:
mesh = o3d.t.geometry.TriangleMesh.from_legacy(mesh).fill_holes().to_legacy()
fill_holes() takes a parameter for max. hole sizes to be closed
http://www.open3d.org/docs/latest/python_api/open3d.t.geometry.TriangleMesh.html#open3d.t.geometry.TriangleMesh.fill_holes

Using Healpy to make star chart

I'm using healpy to plot the locations of galaxies on the sky from a list of RAs and Decs. So far, I think I've been able to correctly plot the galaxies, but I'd like to improve the finished product. Is there any way to bin the number of galaxies that appear in each healpy tile, rather than just coloring being based on whether there is or isn't a catalog member in the tile?
Here I show the image that I'm currently making —
right now it's only really useful for telling you where the Milky Way isn't. Here's the code I'm using.
phis = [np.deg2rad(ra) for ra in ra_list]
thetas = [np.pi / 2 - np.deg2rad(dec) for dec in dec_list]
pixel_indices = hp.ang2pix(NSIDE, thetas, phis)
m = np.zeros(hp.nside2npix(NSIDE))
m[pixel_indices] = np.ones(num_galaxies_to_plot)
hp.mollview(m, title = 'Sky Locations of GLADE Galaxies', cbar = False, rot=(180, 0, 180), cmap = 'binary')
hp.graticule()
You could use numpy.bincount to create an array of the number of galaxies per pixels and then create a map of that.

Determining if a place (given coordinates) is on land or on ocean

I have some coordinates from the ISS (International Space Station) and I'd like to know whether when the coordinates were recorded the ISS was over land or ocean and I should do this offline, but I'm not sure what approach to use.
A part from python standard library, I'm restricted to only using these libraries:
numpy
scipy
tensorflow
pandas
opencv-python
opencv-contrib-python
evdev
matplotlib
logzero
pyephem
scikit-image
scikit-learn
reverse-geocoder
If you know how to do this using some other libraries though, it'd be good anyway.
With this code I get the coordinates and write them to a file:
import logging
import logzero
from logzero import logger
import os
import ephem
import time
dir_path = os.path.dirname(os.path.realpath(__file__))
logzero.logfile(dir_path+"/coordinates.csv")
# Set a custom formatter
formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s');
logzero.formatter(formatter)
name = "ISS (ZARYA)"
line1 = "1 25544U 98067A 18282.18499736 .00001222 00000-0 25998-4 0 9992"
line2 = "2 25544 51.6418 170.6260 0003545 261.4423 234.4561 15.53790940136242"
iss = ephem.readtle(name, line1, line2)
iss.compute()
latitude = iss.sublat
longitude = iss.sublong
# Save the data to the file
logger.info("%s,%s", latitude, longitude )
Do you guys have any idea?
Thanks in advance.
global-land-mask from Karin Todd is extremely easy to use and efficient:
from global_land_mask import globe
print(globe.is_land(49.22, -2.23))
# → True
print(globe.is_land(49.22, -2.25))
# → False
It is available via pip, and its only dependency is numpy.
mpl_toolkits.basemap may be able to help.
from mpl_toolkits.basemap import Basemap
bm = Basemap() # default: projection='cyl'
print(bm.is_land(99.0, 13.0)) #True
print(bm.is_land(0.0, 0.0)) # False
Docs: here and relevant method below:
is_land(xpt, ypt)
Returns True if the given x,y point (in projection coordinates) is over land, False otherwise. The definition of land is based upon the GSHHS coastline polygons associated with the class instance. Points over lakes inside land regions are not counted as land points.
Note: you may need to be careful with the projection that is being used with the Basemap object.
In the end, I was able to solve my problem only using those libraries.
I used this website geoplaner to get a rough outline of the oceans shape (it was really really rough, since I did it by hand, but it worked fine for my purposes, I think online there should be some more accurate polygons but I was lost on how to use them).
I did so for each of the oceans and got this (note that the coordinates I used didn't cover the oceans entirely, for example I avoided the Southern Ocean):
atlanticOcean = [(-24.6,68.5), (25.3,69.8), (5.7,61.4), (4.6,52.2), (-6.3,48.4),
(-9.45,43.5), (-9.63,37.6), (-6.3,35.5), (-10.5,31.1), (-10.5,28.4),
(-16.1,24.5), (-17.2,14.7), (-8.2,4.1), (6.3,3.6), (9.9,3.4),
(9,-1.7), (13.8,-12.6), (11.7,-16.5), (14.5,-22.3), (16.1,-28.67),
(18.9,-34.5), (18.9,-55.7), (-66,-55.7), (-68.5,-50.4), (-58.6,-39.3), (-48.1,-28.2),
(-48.1,-25.7), (-41.6,-22.7), (-38.7,-17.4), (-39.5,-13.7), (-36.9,-12.5),
(-34.9,-10.4), (-35.0,-5.5), (-50,-0.1), (-53,5.5), (-57.2,6.1),
(-62.8,10.9), (-67.8,10.9), (-74.2,10.8), (-76.9,8.5), (-81.6,9.4),
(-82.7,14), (-87.4,16.1), (-86.3,21.6), (-90.2,21.7), (-91.2,19.2),
(-95.7,18.8), (-97.1,25.5), (-91.0,28.9), (-84,29.7), (-82.9,27.3),
(-80.9,24.9), (-79.3,26.7), (-81.1,31.3), (-75.4,35.2), (-73.8,40.3),
(-69.6,41.4), (-65.1,43.5), (-60,45.8), (-52.2,47.1), (-54.9,52.9),
(-44.5,60.1), (-38.8,65.1)]
indianOcean = [(21.40,-34.15), (27.37,-33.71), (40.03,-15.61), (39.68,-3.50), (51.80,10.16),
(58.84,22.26), (65.69,25.18), (71.32,19.83), (77.47,6.86), (80.24,12.53),
(80.90,15.85), (89.05,22.12), (91.38,22.08), (94.54,17.74), (94.02,16.02),
(97.00,16.82), (98.19,8.33), (100.78,3.18), (94.98,6.29), (105.0,-6.52),
(118.16,-9.26), (123.52,-11.25), (129.93,-11.08), (128.62,-14.51), (125.89,-3.57),
(118.51,-20.37), (113.06,-22.18), (115.26,-34.44), (123.52,-34.88), (130.99,-32.09),
(137.23,-36.59), (137.50,-66.47), (102.26,-65.79), (85.65,-66.22), (75.01,-69.50),
(69.04,-67.67), (54.18,-65.76), (37.48,-68.65)]
Now, the Pacific Ocean was more complicated, because it stretches over two sides of a map and you can have two successive points with longitude of -179 and 179 which lead to this polygon to be badly represented in a xy plane. What I did was to divide it in two and so I got this:
pacificEast = [(149.9,-37.8),(153.9,-28.5),(143.2,-11.5),(152.1,-0.9),(127.9,5.7),
(122.9,23.8),(123.4,31),(128.9,33.7),(129.8,29.4),(141.6,35),
(142.8,41),(148,43.3),(144.6,45.5),(146.2,49.3),(144.9,54.2),
(136.8,55.2),(143.1,59.1),(153.7,59.2),(159.4,61.6),(160.3,60.5),
(161.4,60.3),(155.4,57),(156.6,50.3),(160.8,52.8),(164.1,55.8),
(163.8,58.1),(167.3,60.1),(170.7,59.8), (179.9,-77.1),
(166.4,-77.1), (173.8,-71.8), (142.9,-66.8), (146.9,-44.8)]
pacificWest = [(-179.9,62.2),(-179.7,64.7),
(-177.3,65.3),(-173.6,63.4),(-166,62.2),(-165.8,60.9),(-168.4,60.4),
(-166.6,58.9),(-158.5,57.8),(-153.1,57),(-144.8,59.9),(-136.1,56.9),
(-131.7,51.9),(-125.2,48.4),(-124.5,44.6),(-124.4,40.7),(-117.6,32.7),
(-110.7,23.2),(-105.8,19.7),(-96.1,15.3),(-87.9,12.4),(-83.7,7.3),
(-78.7,6.1),(-80.2,0.9),(-82.2,-0.6),(-81.2,-6.3),(-76.7,-14.4),
(-70.4,-18.9),(-73.7,-36.7),(-76,-46.2),(-75.1,-53),(-73.4,-55.1),
(-66.6,-56.3),(-64.6,-55),(-59.6,-63.4),(-68.4,-65.7),(-75.8,-72.2),
(-98.6,-71.8),(-126.8,-73.2),(-146.8,-75.7),(-162.6,-78.4),(-179.9,-77.1)]
As I understand, using matplotlib you can create the polygons from the verteces (the lists of coordinates) with path and then you can use the contains_point() function to check whether the point is in either of the polygons (therefore it's in 'ocean') or not (in 'land'):
p1 = path.Path(atlanticOcean)
p2 = path.Path(indianOcean)
p3 = path.Path(pacificEast)
p4 = path.Path(pacificWest)
target = [(lon, lat)]
result1 = p1.contains_points(target)
result2 = p2.contains_points(target)
result3 = p3.contains_points(target)
result4 = p4.contains_points(target)
# if target is in one of the polygons, it is in ocean
if result1==True or result2==True or result3==True or result4==True:
print("In Ocean")
else:
print("Land")
the lon and lat variables for me where the ones of the ISS which I calculated with the program in my question.

polygon showing up in Google Earth - simpleKML

background - I'm trying to create a circular polygon and add it to a kml using simpleKML.
The kml knows that there should be a polygon added, and it has the proper colour, width, and description, but whenever I zoom to the location it leads me to coordinates 0,0 and no polygon.
My code to create the polygon looks like:
pol = kml.newpolygon(name=pnt.name)
pol.description = ("A buffer for " + pnt.name)
pol.innerboundaryis = [newCoord]
pol.style.linestyle.color = simplekml.Color.green
pol.style.linestyle.width = 5
pol.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.green)
where 'newCoord' is a 2D array with all of the lat/long information stored in it.
Because I thought the array might not format the data properly I tried to form a simple triangular polygon using the code:
pol1 = kml.newpolygon(name=pnt.name)
pol1.innerboundaryis = [(46.714,-75.6667),(44.60796,-74.502),(46.13910,-74.57411),(46.714,-75.6667)]
pol1.style.linestyle.color = simplekml.Color.green
pol1.style.linestyle.width = 5
pol1.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.green)
but it has the same issue as the first.
I've tried forming the polygon with both .innerboundaryis() and .outerboundaryis() without success and I'm running out of ideas.
edit: I should add that I'm opening the kml file in Google Earth
There is almost no documentation on this issue online so I figured I would post the answer to my question for anyone who has this issue in the future.
This is the code that I used that got the polygon working.
newCoords = []
pol = kml.newpolygon(name=pnt.name)
pol.description = ("A buffer for " + pnt.name)
if pnt.name in bufferList:
bufferRange = input('Enter the buffer range. ' )
for i in range(360):
newCoords.append( ( math to calculate Lat, math to calculate Long ) )
pol.outerboundaryis.coords.addcoordinates([newCoords[i]])
pol.style.linestyle.color = simplekml.Color.green
pol.style.linestyle.width = 5
pol.style.polystyle.color = simplekml.Color.changealphaint(100, simplekml.Color.green)
You need to put your coordinates into a list before adding them to the polygon's outer boundary using the 'coords.addcoordinates()' function. Additionally it must be a one dimensional list, so both the latitude and longitude coordinate must be stored in the same place.
You can input floats directly with '.outerboundaryis()', example:
pol.outerboundaryis = [(18.333868,-34.038274), (18.370618,-34.034421),
(18.350616,-34.051677),(18.333868,-34.038274)]
But '.addcoordinates()' only accepts lists and integers.

Cartesian projection issue in a FITS image through PyFITS / AstroPy

I've looked and looked for a solution to this problem and am turning up nothing.
I'm generating rectangular FITS images through matplotlib and subsequently applying WCS coordinates to them using AstroPy (or PyFITS). My images are in galactic latitude and longitude, so the header keywords appropriate for my maps should be GLON-CAR and GLAT-CAR (for Cartesian projection). I've looked at other maps that use this same map projection in SAO DS9 and the coordinates work great... the grid is perfectly orthogonal as it should be. The FITS standard projections can be found here.
But when I generate my maps, the coordinates are not at all Cartesian. Here's a side-by-side comparison of my map (left) and another reference map of roughly the same region (right). Both are listed GLON-CAR and GLAT-CAR in the FITS header, but mine is screwy when looked at in SAO DS9 (note that the coordinate grid is something SAO DS9 generates based on the data in the FITS header, or at least stored somewhere in the FITS file):
This is problematic, because the coordinate-assigning algorithm will assign incorrect coordinates to each pixel if the projection is wrong.
Has anyone encountered this, or know what could be the problem?
I've tried applying other projections (just to see how they perform in SAO DS9) and they come out fine... but my Cartesian and Mercator projections do not come out with the orthogonal grid like they should.
I can't believe this would be a bug in AstroPy, but I can't find any other cause... unless my arguments in the header are incorrectly formatted, but I still don't see how that could cause the problem I'm experiencing. Or would you recommend using something else? (I've looked at matplotlib basemap but have had some trouble getting that to work on my computer).
My header code is below:
from __future__ import division
import numpy as np
from astropy.io import fits as pyfits # or use 'import pyfits, same thing'
#(lots of code in between: defining variables and simple calculations...
#probably not relevant)
header['BSCALE'] = (1.00000, 'REAL = TAPE*BSCALE + BZERO')
header['BZERO'] = (0.0)
header['BUNIT'] = ('mag ', 'UNIT OF INTENSITY')
header['BLANK'] = (-100.00, 'BLANK VALUE')
header['CRVAL1'] = (glon_center, 'REF VALUE POINT DEGR') #FIRST COORDINATE OF THE CENTER
header['CRPIX1'] = (center_x+0.5, 'REF POINT PIXEL LOCATION') ## REFERENCE X PIXEL
header['CTYPE1'] = ('GLON-CAR', 'COORD TYPE : VALUE IS DEGR')
header['CDELT1'] = (-glon_length/x_length, 'COORD VALUE INCREMENT WITH COUNT DGR') ### degrees per pixel
header['CROTA1'] = (0, 'CCW ROTATION in DGR')
header['CRVAL2'] = (glat_center, 'REF VALUE POINT DEGR') #Y COORDINATE OF THE CENTER
header['CRPIX2'] = (center_y+0.5, 'REF POINT PIXEL LOCATION') #Y REFERENCE PIXEL
header['CTYPE2'] = ('GLAT-CAR', 'COORD TYPE: VALUE IS DEGR') # WAS CAR OR TAN
header['CDELT2'] = (glat_length/y_length, 'COORD VALUE INCREMENT WITH COUNT DGR') #degrees per pixel
header['CROTA2'] = (rotation, 'CCW ROTATION IN DEGR') #NEGATIVE ROTATES CCW around origin (bottom left).
header['DATAMIN'] = (data_min, 'Minimum data value in the file')
header['DATAMAX'] = (data_max, 'Maximum data value in the file')
header['TELESCOP'] = ("Produced from 2MASS")
pyfits.update(filename, map_data, header)
Thanks for any help you can provide.
In the modern definition of the -CAR projection (from Calabretta et al.), GLON-CAR/GLAT-CAR projection only produces a rectilinear grid if CRVAL2 is set to zero. If CRVAL2 is not zero, then the grid is curved (this should have nothing to do with Astropy). You can try and fix this by adjusting CRVAL2 and CRPIX2 so that CRVAL2 is zero. Does this help?
Just to clarify what I mean, try, after your code above, and before writing out the file:
header['CRPIX2'] -= header['CRVAL2'] / header['CDELT2']
header['CRVAL2'] = 0.
Any luck?
If you look at the header for the 'reference' file you looked at, you'll see that CRVAL2 is zero there. Just to be clear, there's nothing wrong with CRVAL2 being non-zero, but the grid is then no longer rectilinear.

Categories