inconsistent definition of longitude and latitude for healpy.pixelfunc.get_interp_val() or healpy.mollview()? - healpy

when I rotate a Healpix map along longitude or latitude, I get the wrong behavior.
I'm probably missing something obvious here but so far, I failed to find what.
See demo:
import numpy as np
import healpy as hp
import matplotlib.pyplot as plt
nside = 4
npix = hp.nside2npix(nside)
idx = 70
offset = 1 # rad
# set one pixel to 1 in the map
data = np.array(np.equal(np.arange(npix), idx), dtype=float)
hp.mollview(data, nest=True, title='original')
# longitude and co-latitude in radians
theta, phi = hp.pix2ang(nside, np.arange(npix), nest=True)
# rotate: offset on longitude, keep co-latitude the same
rotated = hp.get_interp_val(data, theta + offset, phi, nest=True)
hp.mollview(rotated, nest=True, title='rotated longitude')
# rotate: keep longitude the same, offset on co-latitude
rotated = hp.get_interp_val(data, theta, phi+offset, nest=True)
hp.mollview(rotated, nest=True, title='rotated latitude')
and results:
original map
rotated longitude
rotated latitude
The dot in the map rotated along longitude is translated vertically, while it is translated horizontally for the rotation along latitude. I'd expect the reverse.
Any hint about what's wrong here?
E.

Theta is co-latitude, Phi is longitude.
It is confusing because their order is inverted than what we usually expect. In fact even in healpy, for example in pix2ang if you set lonlat to true, you get as outputs first Longitude and then Latitude.
Unfortunately this is the convention and we have to stick to this.

Related

How determine optimal epsilon value in meters for DBSCAN by plotting KNN elbow

Before doing DBSCAN I need to find optimal epsilon value, all the points are geographical coordinates, I need the epsilon value in meters before convert it to radians to apply DBSCAN using haversine metrics
from sklearn.neighbors import NearestNeighbors
neigh = NearestNeighbors(n_neighbors=4)
nbrs = neigh.fit(firms[['y', 'x']])
distances, indices = nbrs.kneighbors(firms[['y', 'x']])
AND THEN
# Plotting K-distance Graph
distances = np.sort(distances, axis=0)
distances = distances[:,1]
plt.figure(figsize=(20,10))
plt.plot(distances)
plt.title('K-distance Graph',fontsize=20)
plt.xlabel('Data Points sorted by distance',fontsize=14)
plt.ylabel('Epsilon',fontsize=14)
plt.show()
and the graph output is this, but I need the epsilon value in meters.
I hope this helps to clarify, just a few observations:
a) You are already finding the optimal epsilon value, using that method and from your figure eps = 0.005.
b) If your points are geographic coordinates, you don't need the epsilon value in meters before converting only to then convert to radians so you can apply DBSCAN using haversine metrics, because from the geographic coordinates you can convert straight away to radians, and then you multiply by 6371000/1000 to get the result in kilometers, like this:
from sklearn.metrics.pairwise import haversine_distances
from math import radians
bsas = [-34.83333, -58.5166646]
paris = [49.0083899664, 2.53844117956]
bsas_in_radians = [radians(_) for _ in bsas]
paris_in_radians = [radians(_) for _ in paris]
result = haversine_distances([bsas_in_radians, paris_in_radians])
result * 6371000/1000 # multiply by Earth radius to get kilometers
Code snippet from:
https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.haversine_distances.html

setting right projection crs to geodataframe to calculate in meters

Even though there is an answer to my question How to create an accurate buffer of 5 miles around a coordinate in python?, but I can not represent it.
I have a Series of locations in standart lat, lon float degrees format, and need to calculate buffer around them in meters.
The locations are from Portugal, so I picked up the "right" crs here: https://epsg.io/3763, which is epsg:3763
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['latitude'], df['longitude']),
crs={'init' :'epsg:3763'})
gdf['radius'] = gdf.geometry.buffer(50)
According to the answer above, that should give me polygons around specified radius in meters, but that actually returns radius in the degrees.
I know, that should be simple, but I am still deeply confused. Thank you!
Your Points in the dataframe are lat/lon. You need to initialize the dataframe with the lat/lon crs, then reproject.
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['latitude'], df['longitude']),
crs={'init' :'epsg:4326'})
gdf = gdf.to_crs(epsg=3763)
gdf['radius'] = gdf.geometry.buffer(50)

How do I perform a curve fit with an array of points and touching a specific point in that array

I need help with curve fitting a given set of points. The points form a parabola and I ought to find the peak point of the result. Issue is when I do a curve fit, it sometimes doesn't touch the max y-coordinate even if the actual point is given in the input array.
Following is the code snippet. Here 1.88 is the actual peak y-coordinate (13.05,1.88). But the graph generated by the code does not touch the point due to curve fitting. So is there a way to fit the curve making sure that it touches the max point given in the input array?
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit, minimize_scalar
fig = plt.gcf()
#fig.set_size_inches(18.5, 10.5)
x = [4.59,9.02,13.05,18.47,20.3]
y = [1.7,1.84,1.88,1.7,1.64]
def f(x, p1, p2, p3):
return p3*(p1/((x-p2)**2 + (p1/2)**2))
plt.plot(x,y,"ro")
popt, pcov = curve_fit(f, x, y)
# find the peak
fm = lambda x: -f(x, *popt)
r = minimize_scalar(fm, bounds=(1, 5))
print( "maximum:", r["x"], f(r["x"], *popt) ) #maximum: 2.99846874275 18.3928199902
plt.text(1,1.9,'maximum '+str(round(r["x"],2))+'( #'+str(round(f(r["x"], *popt),2)) + ' )')
x_curve = np.linspace(min(x), max(x), 50)
plt.plot(x_curve, f(x_curve, *popt))
plt.plot(r['x'], f(r['x'], *popt), 'ko')
plt.show()
Here is a graphical code example using your equation with weighted fitting, where I have made the max point larger to more easily see the effect of the weighting. In non-weighted curve fitting, all weights are implicitly 1.0 as all data points have equal weight. Scipy's curve_fit routine uses weights in the form of uncertainties, so that giving a point a very small uncertainty (which I have done) is like giving the point a very large weight. This technique can be used to make a fit pass arbitrarily close to any single data point by any software that can perform weghted fitting.
import numpy, scipy, matplotlib
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = [4.59,9.02,13.05,18.47,20.3]
y = [1.7,1.84,2.0,1.7,1.64]
# note the single very small uncertainty - try making this value 1.0
uncertainties = numpy.array([1.0, 1.0, 1.0E-6, 1.0, 1.0])
# rename data to use previous example
xData = numpy.array(x)
yData = numpy.array(y)
def func(x, p1, p2, p3):
return p3*(p1/((x-p2)**2 + (p1/2)**2))
# these are the same as the scipy defaults
initialParameters = numpy.array([1.0, 1.0, 1.0])
# curve fit the test data, first without uncertainties to
# get us closer to initial starting parameters
ssqParameters, pcov = curve_fit(func, xData, yData, p0 = initialParameters)
# now that we have better starting parameters, use uncertainties
fittedParameters, pcov = curve_fit(func, xData, yData, p0 = ssqParameters, sigma=uncertainties, absolute_sigma=True)
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # squared errors
MSE = numpy.mean(SE) # mean squared errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))
print('Parameters:', fittedParameters)
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
print()
##########################################################
# graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
axes = f.add_subplot(111)
# first the raw data as a scatter plot
axes.plot(xData, yData, 'D')
# create data for the fitted equation plot
xModel = numpy.linspace(min(xData), max(xData))
yModel = func(xModel, *fittedParameters)
# now the model as a line plot
axes.plot(xModel, yModel)
axes.set_xlabel('X Data') # X axis data label
axes.set_ylabel('Y Data') # Y axis data label
plt.show()
plt.close('all') # clean up after using pyplot
graphWidth = 800
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)

SDO Geometry. Calculate shortest distance

I have coordinates of place stored as struct object and coordinates of buildings stored as Doubles.
select geo.id, geo.object_id, geo.object_type, geo.date_created, t.x as longitude, t.y as latitude from geolocation geo, table(sdo_util.getvertices(geo.location)) t; --I can fetch places coordinates.
select longitude, latitude from building -- Fetch buildings locations.
I have to find in which building this place is located (the shortest distance to the near building).
i.e.
Place: longitude = 41.1111111, langitude = 42.2222222
Building 1: longitude = 41.1111112, langitude = 42.42.2222223
Building 2: longitude = 50.1111111, langitude = 50.2222222
Building 3: longitude = 60.1111111, langitude = 60.2222222
(I exaggerated values deliberately)
The result should be: building 1 (this is the near building).
How can I use SDO_GEOM.SDO_DISTANCE ?
Sorry. I know nothing about SDO_GEOM. But I can show a few maths, if that helps:
Define a vector centre-of-Earth to point1. Define another vector with the centre-of-Earth and another point. The dot product of both vectors gives you the cosine of the angle between these two vectors.
The point with maximum dot-product is the closest point to point1.
For dot product with spherical coordinates see this post.
You can take the aproximation that all vectors have the same r. Because you are interested in maximum values (not real distances) you can use r1 = r2 = 1
Also, in that post φ = 90 - latitude. Remember sin(a) = cos(90-a).
Doing both corrections the final formula you need is
d = cosφ1 cosφ2 cos(θ1−θ2) + sinφ1 sinφ2
with φ = latitude and θ = longitude

Compute equidistant GPS point around a center

I have a question about some GPS calculations.
My problem is as follow :
I have a specific point P, and I want to compute N points around P.
Here is the algorithm :
P = (x, y) // latitude, longitude
N = 8
angle_size = 360/N
points = []
for i in 1..N
points.push compute_100meter(P, angle_size*i)
end
In this example, I'm trying to compute 8 equidistant point within 100 meter from P.
Is anyone know a ruby gem allowing me to do so ?
My problem is to write the content of compute_100meter
EDIT:
I have to take into account the earth curvature and get the point coordinates in degree (latitude, longitude).
As long as the radius is small enough (and 100 meters should be, unless you're right next to the north or south pole), a simple linear approximation should do well enough:
def perimeter_point(lat, lon, angle, radius)
# convert angle from degrees to radians
angle *= Math::PI / 180
# convert meters to degrees approximately, assuming spherical Earth
radius /= 6371000 * Math::PI / 180
# calculate relative length of the circle of longitude compared to equator
scale = Math.cos( lat * Math::PI / 180 );
# add offsets to longitude and latitude and return them
# (I'm assuming that angle = 0 means due east)
lat += radius * Math.sin(angle)
lon += radius * Math.cos(angle) / scale
return lat, lon
end
Note that, if your center point is near the 180th meridian, this could return longitudes below -180 or above +180. If that's a problem, check for it and normalize as needed. (Output latitudes outside the ±90 range are also technically possible, if the center point is near the north or south pole, but the approximation I used breaks down close to the poles anyway.)

Resources