Django: How do i store a geo point in database - django

Needed correct datatype for geo points.
I will get and display it with google map API so format like
42.761819,11.104863
41.508577,-101.953125
Usecase:
user click on map
django save this point with additional data
on next visiting django display this points on map
So, no distances beetween points and etc hacks.
DB: postgres 8
Django: 1.4

Check out GeoDjango and see if it helps you. If your stack is configured to run GeoDjango, you can do this.
Your models will looks like this
from django.contrib.gis.db import models
class LocationPoint(models.Model):
point = models.PointField(srid=4326,dim=3)
accuracy = models.FloatField(default=0.0)
objects = models.GeoManager()
To save the point to the database all you will have to do is
from django.contrib.gis.geos import Point
point = Point(x=12.734534, y=77.2342, z=0, srid=4326)
location = LocationPoint()
location.point = point
location.save()
GeoDjango gives you extended abilities to do geospatial queries which you might be interested in the near future, like finding the distance between points, finding the nearest locations around a point etc.
Here's the link to GeoDjango

From django documentation about DecimalField:
DecimalField.max_digits
The maximum number of digits allowed in the
number. Note that this number must be greater than or equal to
decimal_places.
DecimalField.decimal_places
The number of decimal places to store with
the number.
which is refering to the Python Decimal
To make good choice about accurate data type and precission you should consider:
what is minimum possible value (latitude can be from 0 (down)up to (-)90 degrees) _ _.
what is maximum possible value (longitude can range from 0 (down)up to (-)180 degrees) _ _ _.
what is accuracy (decimal_places), you wish. Pleas notice that it has impact on zoom level on Google Maps.
By the way, for better understanding, it is good to know how the calculation is done (Python code):
def deg_to_dms(deg):
d = int(deg)
md = abs(deg - d) * 60
m = int(md)
sd = (md - m) * 60
return [d, m, sd]
def decimal(deg,min,sec):
if deg < 0:
dec= -1.0 * deg + 1.0 * min/60.0 + 1.0 * sec/3600.0
return -1.0 * dec
else:
dec=1.0 * deg + 1.0 * min/60.0 + 1.0 * sec/3600.0;
return dec

It looks like you're going to be storing a latitude and a longitude. I would go with a DecimalField for this, and store each number separately.

I use longitude and latitude in my django setup.
My model includes:
long_position = models.DecimalField (max_digits=8, decimal_places=3)
lat_position = models.DecimalField (max_digits=8, decimal_places=3)
For more precision you may want the decimal_places to be more.
When you want to display it in the Google Map API method you would reference your model and write a python code to output like this:
output = some_long_position + "," + some_lati_position

I'm using this in model
latitude = models.DecimalField(max_digits=11, decimal_places=7,null=True,blank=True)
longitude = models.DecimalField(max_digits=11, decimal_places=7,null=True,blank=True)

Related

Update weights by different models

I have the following problem:
I must identify if a data point is an outlier or not (we don't have labels). I have different unsupervised models to identify the outlier. Then, I normalize the outlier score and I combine them via a weight average. According to the fact that I don't have information about their accuracy I use the same weight for each models.
Now, suppose that I have a small fraction of the dataset with also the label.
How can I update the weights according to the new information?
Please If you have it, give me some resources because I didn't find it.
Thank you in advance.
I tried to see some resources about the bayesian model average, but I don't know If it is the correct way. I also have implemented an idea, but I'm not sure that is correct.
import numpy as np
def bayesian_update(anomaly, weight, prob):
#posterior = prob(anomaly | model)
posterior = np.zeros(len(anomaly))
for i in range(len(anomaly)):
if anomaly[i] == 1:
posterior[i] = prob[i] * weight
else:
posterior[i] = (1-prob[i]) * weight
return posterior
np.random.seed(0)
n_observations = 100
n_models = 4
#
models_probs = np.random.rand(n_observations, n_models)
anomaly = np.where(models_probs[:, 0] > 0.5, 1, 0)
posterior_sum = np.zeros(n_models)
for i in range(n_models):
posterior_sum[i] = np.sum(bayesian_update(anomaly, 0.25, models_probs[:, i]))
new_weight = posterior_sum/np.sum(posterior_sum)
print(new_weight)

How to do location based query with simple Django filter?

I've saved user's coordinates in the User model. Post model has latitude, longitude and radius field. Only the users in that vicinity(of Post) will be able to see that post. I don't know how to use filter() here so I used the following approach:
post=Posts.objects.all()
for a in post:
distance= geopy.distance.geodesic((lat1,lng1), (a.latitude, a.longitude)).km
print(distance)
if distance < a.radius:
p.append(a)
else:
continue
Here, lat1 and lng1 are the coordinates of current User. Suggest if there is any better way as this seems very inefficient.
Depending on your requirements, you could use a square instead of a circle. Pre-calculate the x-max, x-min, y-max and y-min boundaries for your square and then do a simple User.filter(lat__gt=lat_min, user.lng__gt=lng_min, user.lat__lt=lat_max ... lookup in the database.
In a past project, I used this:
def get_latlng_bounderies(lat, lng, distance):
"""
Return min/max lat/lng values for a distance around a latlng.
:lat:, :lng: the center of the area.
:distance: in km, the "radius" around the center point.
:returns: Two corner points of a square that countains the circle,
lat_min, lng_min, lat_max, lng_max.
"""
gc = great_circle(kilometers=distance)
p0 = gc.destination((lat, lng), 0)
p90 = gc.destination((lat, lng), 90)
p180 = gc.destination((lat, lng), 180)
p270 = gc.destination((lat, lng), 270)
ret = p180[0], p270[1], p0[0], p90[1]
return ret
Its not a circle, so its not exact around the "corners" of the square, but its much faster, because its a simple float comparision in the database.

Calculating distance between two PointField (s) - Why is my result incorrect?

I am trying to calculate the distance between two locations in miles however the result that I am getting is incorrect.
The reason I think its incorrect is because I put locations (latitude and longitude) on this website and I get the distance in miles as 0.055. Here are the details from my code
PointField A : (-122.1772784, 47.7001663)
PointField B : (-122.1761632, 47.700408)
Distance : 0.001141091551967795
However, according to the website, the distance should be
Distance: 0.055 miles
Here is how I am calculating the distance.
This is my model
class modelEmp(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
location = models.PointField(srid=4326,max_length=40, blank=True, null=True)
objects = GeoManager()
and this is how I calculate the distance
result = modelEmpInstance.location.distance(PointFieldBLocation)
where result = 0.001141091551967795
Any suggestions on what I might be doing wrong here and why my result is different from the website?
Your calculation is not wrong but the result is in the EPSG:4326's units, which are degrees. In order to calculate the distance in the wanted unit, we need to do the following:
Transform the points into an EPSG with meter units.
If you don't care much about the accuracy of the calculations, you can use the EPSG:3857 (but the result will be 0.08104046068988752mi).
If you do care about the accuracy of your calculation though, you need to find an EPSG with meter units that are appropriate for your location. Since your points are located around the Seattle area, the appropriate EPSG is 32148.
Create a Distance object with the distance calculation in meters
Finally, convert it to miles:
from django.contrib.gis.measure import Distance
result = Distance(
m = modelEmpInstance.location.transform(
32148, clone=True
).distance(PointFieldBLocation.transform(32148, clone=True)
)
print(
'Raw calculation: {}\nRounded calculation: {}'
.format(result.mi, round(result.mi, 2)
)
This will print:
Raw calculation: 0.0546237743898667
Rounded calculation: 0.055

PVLIB - DC Power From Irradiation - Simple Calculation

Dear pvlib users and devels.
I'm a researcher in computer science, not particularly expert in the simulation or modelling of solar panels. I'm interested in use pvlib since
we are trying to simulate the works of a small solar panel used for IoT
applications, in particular the panel spec are the following:
12.8% max efficiency, Vmp = 5.82V, size = 225 × 155 × 17 mm.
Before using pvlib, one of my collaborator wrote a code that compute the
irradiation directly from average monthly values calculated with PVWatt.
I was not really satisfied, so we are starting to use pvlib.
In the old code, we have the power and current of the panel calculated as:
W = Irradiation * PanelSize(m^2) * Efficiency
A = W / Vmp
The Irradiation, in Madrid, as been obtained with PVWatt, and this is
what my collaborator used:
DIrradiance = (2030.0,2960.0,4290.0,5110.0,5950.0,7090.0,7200.0,6340.0,4870.0,3130.0,2130.0,1700.0)
I'm trying to understand if pvlib compute values similar to the ones above, as averages over a day for each month. And the curve of production in day.
I wrote this to compare pvlib with our old model:
import math
import numpy as np
import datetime as dt
import matplotlib.pyplot as plt
import pandas as pd
import pvlib
from pvlib.location import Location
def irradiance(day,m):
DIrradiance =(2030.0,2960.0,4290.0,5110.0,5950.0,
7090.0,7200.0,6340.0,4870.0,3130.0,2130.0,1700.0)
madrid = Location(40.42, -3.70, 'Europe/Madrid', 600, 'Madrid')
times = pd.date_range(start=dt.datetime(2015,m,day,00,00),
end=dt.datetime(2015,m,day,23,59),
freq='60min')
spaout = pvlib.solarposition.spa_python(times, madrid.latitude, madrid.longitude)
spaout = spaout.assign(cosz=pd.Series(np.cos(np.deg2rad(spaout['zenith']))))
z = np.array(spaout['cosz'])
return z.clip(0)*(DIrradiance[m-1])
madrid = Location(40.42, -3.70, 'Europe/Madrid', 600, 'Madrid')
times = pd.date_range(start = dt.datetime(2015,8,15,00,00),
end = dt.datetime(2015,8,15,23,59),
freq='60min')
old = irradiance(15,8) # old model
new = madrid.get_clearsky(times) # pvlib irradiance
plt.plot(old,'r-') # compare them.
plt.plot(old/6.0,'y-') # old seems 6 times more..I do not know why
plt.plot(new['ghi'].values,'b-')
plt.show()
The code above compute the old irradiance, using the zenit angle. and compute the ghi values using the clear_sky. I do not understand if the values in ghi must be multiplied by the cos of zenit too, or not. Anyway
they are smaller by a factor of 6. What I'd like to have at the end is the
power and current in output from the panel (DC) without any inverter, and
we are not really interested at modelling it exactly, but at least, to
have a reasonable curve. We are able to capture from the panel the ampere
produced, and we want to compare the values from the measurements putting
the panel on the roof top with the values calculated by pvlib.
Any help on this would be really appreachiated. Thanks
Sorry Will I do not care a lot about my previous model since I'd like to move all code to pvlib. I followed your suggestion and I'm using irradiance.total_irrad, the code now looks in this way:
madrid = Location(40.42, -3.70, 'Europe/Madrid', 600, 'Madrid')
times = pd.date_range(start=dt.datetime(2015,1,1,00,00),
end=dt.datetime(2015,1,1,23,59),
freq='60min')
ephem_data = pvlib.solarposition.spa_python(times, madrid.latitude,
madrid.longitude)
irrad_data = madrid.get_clearsky(times)
AM = atmosphere.relativeairmass(ephem_data['apparent_zenith'])
total = irradiance.total_irrad(40, 180,
ephem_data['apparent_zenith'], ephem_data['azimuth'],
dni=irrad_data['dni'], ghi=irrad_data['ghi'],
dhi=irrad_data['dhi'], airmass=AM,
surface_type='urban')
poa = total['poa_global'].values
Now, I know the irradiance on POA, and I want to compute the output in Ampere: It is just
(poa*PANEL_EFFICIENCY*AREA) / VOLT_OUTPUT ?
It's not clear to me how you arrived at your values for DIrradiance or what the units are, so I can't comment much the discrepancies between the values. I'm guessing that it's some kind of monthly data since there are 12 values. If so, you'd need to calculate ~hourly pvlib irradiance data and then integrate it to check for consistency.
If your module will be tilted, you'll need to convert your ~hourly irradiance GHI, DNI, DHI values to plane of array (POA) irradiance using a transposition model. The irradiance.total_irrad function is the easiest way to do that.
The next steps depend on the IV characteristics of your module, the rest of the circuit, and how accurate you need the model to be.

GeoDjango: Determine the area of a polygon

In my model I have a polygon field defined via
polygon = models.PolygonField(srid=4326, geography=True, null=True, blank=True)
When I want to determine the area of the polygon, I call
area_square_degrees = object.polygon.area
But how can I convert the result in square degrees into m2 with GeoDjango?
This answer does not work, since area does not have a method sq_m. Is there any built-in conversion?
You need to transform your data to the correct spatial reference system.
area_square_local_units = object.polygon.transform(srid, clone=False).area
In the UK you might use the British National Grid SRID of 27700 which uses meters.
area_square_meters = object.polygon.transform(27700, clone=False).area
You may or may not want to clone the geometry depending on whether or not you need to do anything else with it in its untransformed state.
Docs are here https://docs.djangoproject.com/en/1.8/ref/contrib/gis/geos/
I have struggled a lot with this, since i could'nt find a clean solution. The trick is you have to use the postgis capabilities (and and thus its only working with postgis..):
from django.contrib.gis.db.models.functions import Area
loc_obj = Location.objects.annotate(area_=Area("poly")).get(pk=??)
# put the primary key of the object
print(loc_obj.area_) # distance object, result should be in meters, but you can change to the unit you want, e.g .mi for miles etc..
The models.py:
class Location(models.Model):
poly = gis_models.PolygonField(srid=4326, geography=True)
It's i think the best way to do it if you have to deal with geographic coordinates instead of projections. It does handle the curve calculation of the earth, and the result is precise even with big distance/area
I needed an application to get the area of poligons around the globe and if I used an invalid country/region projection I got the error OGRException: OGR failure
I ended using an OpenLayers implementation
using the 4326 projection (is the default projection) to avoid concerning about every country/region specific projection.
Here is my code:
import math
def getCoordsM2(coordinates):
d2r = 0.017453292519943295 # Degrees to radiant
area = 0.0
for coord in range(0, len(coordinates)):
point_1 = coordinates[coord]
point_2 = coordinates[(coord + 1) % len(coordinates)]
area += ((point_2[0] - point_1[0]) * d2r) *\
(2 + math.sin(point_1[1] * d2r) + math.sin(point_2[1] * d2r))
area = area * 6378137.0 * 6378137.0 / 2.0
return math.fabs(area)
def getGeometryM2(geometry):
area = 0.0
if geometry.num_coords > 2:
# Outer ring
area += getCoordsM2(geometry.coords[0])
# Inner rings
for counter, coordinates in enumerate(geometry.coords):
if counter > 0:
area -= getCoordsM2(coordinates)
return area
Simply pass your geometry to getGeometryM2 function and you are done!
I use this function in my GeoDjango model as a property.
Hope it helps!
If Its earths surface area that you are talking about, 1 square degree has 12,365.1613 square km. So multiple your square degree and multiply by 10^6 to convert to meters.