Get City, State, Country from Latitude and Longitude in Google Sheets - google-sheets

In Google Sheets, I have a column with latitude and longitude coordinates. The list goes from A2:A1000. I also have columns for City, State, and Country in B1, C1, and D1, respectively. Is there a formula or script I can run that reads the coordinates and provides the city, state, and country in their respective column? I do not know how to use JavaScript, XML, JSON, serialized PHP, etc. so if your suggestion includes one of those, please provide some instructions. Thanks in advance.

Well, I have a psuedo-solution. Go into Google Spreadsheets > Tools > Script Editor and paste the following code into a blank project:
function reverse_geocode(lat,lng) {
Utilities.sleep(1500);
var response = Maps.newGeocoder().reverseGeocode(lat,lng);
for (var i = 0; i < response.results.length; i++) {
var result = response.results[i];
Logger.log('%s: %s, %s', result.formatted_address, result.geometry.location.lat,
result.geometry.location.lng);
return result.formatted_address;
}
}
Then in the spreadsheet, use this formula:
=reverse_geocode(latitude_goes_here,longitude_goes_here)
For example, if I have the latitude in A2 and longitude in B2:
=reverse_geocode(A2,B2)
This will provide the full address. I'm now trying to figure out how to parse the country from the address.

Based on #gabriel-rotman solution.
Go into Google Spreadsheets > Tools > Script Editor and paste the following code into a blank project:
/**
* Return the closest, human-readable address type based on the the latitude and longitude values specified.
*
* #param {"locality"} addressType Address type. Examples of address types include
* a street address, a country, or a political entity.
* For more info check: https://developers.google.com/maps/documentation/geocoding/intro#Types
* #param {"52.379219"} lat Latitude
* #param {"4.900174"} lng Longitude
* #customfunction
*/
function reverseGeocode(addressType, lat, lng) {
Utilities.sleep(1500);
if (typeof addressType != 'string') {
throw new Error("addressType should be a string.");
}
if (typeof lat != 'number') {
throw new Error("lat should be a number");
}
if (typeof lng != 'number') {
throw new Error("lng should be a number");
}
var response = Maps.newGeocoder().reverseGeocode(lat, lng),
key = '';
response.results.some(function (result) {
result.address_components.some(function (address_component) {
return address_component.types.some(function (type) {
if (type == addressType) {
key = address_component.long_name;
return true;
}
});
});
});
return key;
}
Then in the spreadsheet, use this formula:
=reverseGeocode(address_type; latitude_goes_here; longitude_goes_here)
For example, if I have the latitude in A2 and longitude in B2 and that I want to get the city then I can use:
=reverseGeocode("locality"; A2; B2)
If you want the country you can use:
=reverseGeocode("country"; A2; B2)
Bonus function to extract part of an address:
/**
* Return the closest, human-readable address type based on the the address passed.
*
* #param {"locality"} addressType Address type. Examples of address types include
* a street address, a country, or a political entity.
* For more info check: https://developers.google.com/maps/documentation/geocoding/intro#Types
* #param {"Amsterdam"} address The street address that you want to geocode,
* in the format used by the national postal service
* of the country concerned. Additional address elements
* such as business names and unit, suite or floor
* numbers should be avoided.
* #customfunction
*/
function geocode(addressType, address) {
if (typeof addressType != 'string') {
throw new Error("addressType should be a string.");
}
if (typeof address != 'string') {
throw new Error("address should be a string.");
}
var response = Maps.newGeocoder().geocode(address),
key = "";
response.results.some(function (result) {
return result.address_components.some(function (address_component) {
return address_component.types.some(function (type) {
if (type === addressType) {
key = address_component.long_name;
}
});
});
});
return key;
}

Related

node-red-node-firebird returns a buffer instead of a string

I'm doing KPI's in node-red, and I'm using node-red-node-firebird to connect my database and get the results from it. For that I made a query to select the columns I need, one of those is:
NAME Varchar(40), with an example value: "Pizzas"
(example: Select NAME from mytable)
When I receive the query response on node-red, I store it inside the msg.payload. The problem is the result that I get it isn't the string "Pizzas" but a buffer "NAME":{"type":"Buffer","data":[80,105,122,122,97,115]}}.
How can I get the string and not the buffer?
I already tried a lot of things, among them:
On the query I have tried cast(NAME AS varchar(40)) AS NAME; [NAME] without success. Put msg.payload.data.toString('utf-8') in function node but nothing happens, the function:
var objectData = msg.objectData; //this is the query response
//------------Columns----------------------------
var fields = [];
var i = 0;
if(objectData.length > 0) {
var data = objectData[0];
for(var key in data) {
fields[i] = key;
i++;
}
//TRY nº1
objectData.foreach(function(obj){
if (Buffer.isBuffer(obj) === true) {
obj = obj.toString('utf-8');
}
})
}
//-----------------------------------------
msg.method = "POST";
msg.url = //My api request//;
msg.headers = {};
msg.headers["Content-Type"] = "application/json";
msg.headers.Authorization = //auth//;
msg.payload = {
'groupID': 'Group123',
'companyID': 1221,
'table': 'DemoTable',
'fields': fields,
'data': objectData, //problem
'delete': true,
};
//TRY nº2
msg.payload = msg.payload.data.toString('utf-8');
return msg;
I solved my problem changing the select to:
SELECT cast(name as varchar(100) character set win1252) NOME FROM mytable
Thanks for the help :)

Using GSheets Script to increment value of duplicate by 1

I want to check a row for duplicates and if match increment these by 1.
The data I want to manipulate this way is LAT LONG Coordinates.
They originate from an aggregated data acquisition, where users can only insert country and city. Via an Add-On these will get GEO coded.
Problem is, that I need to slightly change the values of duplicate entries, in order to display them on a map. Easiest way (I think) is to increment a LAT or LONG coordinate by 1 if there is already an entry with the same value.
Data sample & results of script
Any idea how to do this via Script?
My code, originally intended to delete duplicate rows:
function overwriteDuplicates() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Formularantworten 2");
var vA=sh.getDataRange().getValues();
var hA=vA[0];
var hObj={};
hA.forEach(function(e,i){hObj[e]=i;});//header title to index
var uA=[];
var d=0;
for(var i=0;i<vA.length;i++) {
if(uA.indexOf(vA[i][hObj['Latitude']])==-1) {
uA.push(vA[i][hObj['Latitude']]);
}else{
function increment() {
SpreadsheetApp.getActiveSheet().getRange('K').setValue(SpreadsheetApp.getActiveSheet().getRange('K').getValue() + 1);
}
}}}
You want to modify the latitude whenever duplicate coordinates (latitude and longitude is found).
In this case, you can do the following:
Get all the values in the sheet, and retrieve the indexes where Latitude and Longitude are, based on the headers.
Loop through all rows (excluding headers), and for each row, check whether a previous row contains these coordinates.
If that's the case (isDuplicate), increment the last number in the latitude (after the last .), or decrement it if it's close to 999 (I assume there's always 3 digits).
Store the new latitude in an array after modification.
Use setValues to write the modified latitudes to the sheet.
Below is a possible code snippet to do this (see inline comments for details).
Code snippet:
function overwriteDuplicates() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName("Formularantworten 2");
const values = sheet.getDataRange().getValues();
const headers = values.shift(); // Retrieve first row (headers)
const latColumn = headers.indexOf("Latitude"); // Latitude column index
const longColumn = headers.indexOf("Longitude"); // Longitude column index
let outputLocations = [];
for (let i = 0; i < values.length; i++) { // Loop through rows
const newLocation = { // Store object with current location
"latitude": values[i][latColumn],
"longitude": values[i][longColumn]
}
let isDuplicate;
do { // Check if location is duplicate, and increment if necessary
isDuplicate = outputLocations.some(location => {
const sameLatitude = location["latitude"] === newLocation["latitude"];
const sameLongitude = location["longitude"] === newLocation["longitude"];
return sameLatitude && sameLongitude;
});
if (isDuplicate) newLocation["latitude"] = modifyCoord(newLocation["latitude"]);
} while (isDuplicate);
outputLocations.push(newLocation); // Store new location in array
}
let outputLatitudes = outputLocations.map(location => [location["latitude"]]); // Retrieve latitudes from array
sheet.getRange(2, latColumn+1, sheet.getLastRow()-1).setValues(outputLatitudes); // Write updated latitudes to sheet
}
function modifyCoord(coordinates) {
let coordArray = coordinates.split(".");
let lastCoord = coordArray.pop();
if (lastCoord > 990) lastCoord--;
else lastCoord++;
coordArray.push(lastCoord);
return coordArray.join(".");
}
Output:

Need timezone based on the ISO country code and city in Java

My requirement
::: To find the timezone based on the city and country code both. Please share Is there any way to find it? I don't want to go with city only since one city can exist in two or more countries.
And even on city bases - I can find time zone but not for all cities if i am entering Leeds (UK city) , its giving nothing.
Set<String> availableTimeZones = ZoneId.getAvailableZoneIds();
String cityName = Normalizer.normalize(city, Normalizer.Form.NFKD).replaceAll("[^\\p{ASCII}-_ ]", "")
.replace(' ', '_');
List<String> possibleTimeZones = availableTimeZones.stream().filter(zid -> zid.endsWith("/" + cityName))
.collect(Collectors.toList());
Rough way I found to achieve is -
private static String getSourceLocalTimeZone(String countryCode, String city, String sourceLocalTimeZone) {
String[] timeZones = com.ibm.icu.util.TimeZone.getAvailableIDs(countryCode);
for (String timeZone : timeZones) {
String cityFromTimeZone = null;
String[] value = timeZone.split("/");
if (value != null && value.length > 0) {
cityFromTimeZone = value[value.length - 1].replace("_", " ");
}
if (city!=null && city.matches("(.*)" + cityFromTimeZone + "(.*)")) {
sourceLocalTimeZone = timeZone;
break;
}
}
if (sourceLocalTimeZone == null || (sourceLocalTimeZone.isEmpty())) {
if(timeZones.length>0)
sourceLocalTimeZone = timeZones[0];
}
return sourceLocalTimeZone;
}
Dependency -
<dependency>
<groupId>com.ibm.icu</groupId>
<artifactId>icu4j</artifactId>
<version>4.6</version>
</dependency>

get address line in Arabic from coordinates

Am using Geocoder plugin to get address line, country, postal code, .... like this:
final coordinates = new Coordinates(26.328446, 50.153868);
var addresses = await Geocoder.local.findAddressesFromCoordinates(coordinates);
var first = addresses.first;
print(addresses);
print("${first.featureName} : ${first.addressLine}");
and this returns:
flutter: Zarqa Al Yamamah Street : Zarqa Al Yamamah Street - Al Dana Al Jenobiah, Dhahran 34453, Saudi Arabia
I want to get the same result but in Arabic .. is there is a way to achieve this with this plugin? or there is any other plugins can return address for me in Arabic?
You can get the language code ar or ar-SA. So you need to do this:
Locale loc = new Locale("ar");
Geocoder geocoder = new Geocoder(this, loc);
or this way
geocoder = new Geocoder(this, Locale.ar_SA))
Your code can be like this
Locale loc = new Locale("ar");
Geocoder geocoder = new Geocoder(this, loc))
final coordinates = new Coordinates(26.328446, 50.153868);
var addresses = await Geocoder.local.findAddressesFromCoordinates(coordinates);
var first = addresses.first;
print(addresses);
print("${first.featureName} : ${first.addressLine}");
Do it like this:
Geocoder geocoder;
List<Address> addresses;
geocoder = new Geocoder(this, Locale.ar_SA))
addresses = geocoder.getFromLocation(latitude, longitude, 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName(); // Only if available else return NULL
See this example:
import 'package:locales/locales.dart';
import 'package:locales/currency_codes.dart';
import 'package:intl/intl.dart';
void main() {
final locale = Locale.ar_SA;
final currencyCode = CurrencyCode.sar;
final format = NumberFormat.simpleCurrency(
locale: '$locale', name: '$currencyCode', decimalDigits: 2);
print(locale);
print(currencyCode);
print(format.format(123.456));
}
https://github.com/jifalops/locales
If you want to use specific local you must use apiKey
try to replace Geocoder.local method with Geocoder.google in your code
Like this :
Coordinates coordinates = Coordinates(latLng.lat, latLng.lng);
List<Address> addresses =await Geocoder.google(apiKey,language:'ar').findAddressesFromCoordinates(coordinates);
How to get apiKey ? show Get an API Key

Google docs to google sheets script

I’m using Google Sheets to conduct some text analysis. I would like to automate the process by linking a spreadsheet to a Google doc file on my GDrive to extract text directly. It doesn’t have to structured/formatted. It just has to be a plain text. Does it take a comprehensive scripting or the task of copying text is simple?
I searched the web but couldn’t find one.
To help you start, here is an SO thread.
Same scenario: Get data from the Google Sheets and copy it to the Google Docs.
A reference from Open Source Hacker: Script for generating Google documents from Google spreadsheet data source.
Here is the code provided in the article. You can modify it by yourself depending on your use.
/**
* Generate Google Docs based on a template document and data incoming from a Google Spreadsheet
*
* License: MIT
*
* Copyright 2013 Mikko Ohtamaa, http://opensourcehacker.com
*/
// Row number from where to fill in the data (starts as 1 = first row)
var CUSTOMER_ID = 1;
// Google Doc id from the document template
// (Get ids from the URL)
var SOURCE_TEMPLATE = "xxx";
// In which spreadsheet we have all the customer data
var CUSTOMER_SPREADSHEET = "yyy";
// In which Google Drive we toss the target documents
var TARGET_FOLDER = "zzz";
/**
* Return spreadsheet row content as JS array.
*
* Note: We assume the row ends when we encounter
* the first empty cell. This might not be
* sometimes the desired behavior.
*
* Rows start at 1, not zero based!!! 🙁
*
*/
function getRowAsArray(sheet, row) {
var dataRange = sheet.getRange(row, 1, 1, 99);
var data = dataRange.getValues();
var columns = [];
for (i in data) {
var row = data[i];
Logger.log("Got row", row);
for(var l=0; l<99; l++) {
var col = row[l];
// First empty column interrupts
if(!col) {
break;
}
columns.push(col);
}
}
return columns;
}
/**
* Duplicates a Google Apps doc
*
* #return a new document with a given name from the orignal
*/
function createDuplicateDocument(sourceId, name) {
var source = DocsList.getFileById(sourceId);
var newFile = source.makeCopy(name);
var targetFolder = DocsList.getFolderById(TARGET_FOLDER);
newFile.addToFolder(targetFolder);
return DocumentApp.openById(newFile.getId());
}
/**
* Search a paragraph in the document and replaces it with the generated text
*/
function replaceParagraph(doc, keyword, newText) {
var ps = doc.getParagraphs();
for(var i=0; i<ps.length; i++) {
var p = ps[i];
var text = p.getText();
if(text.indexOf(keyword) >= 0) {
p.setText(newText);
p.setBold(false);
}
}
}
/**
* Script entry point
*/
function generateCustomerContract() {
var data = SpreadsheetApp.openById(CUSTOMER_SPREADSHEET);
// XXX: Cannot be accessed when run in the script editor?
// WHYYYYYYYYY? Asking one number, too complex?
//var CUSTOMER_ID = Browser.inputBox("Enter customer number in the spreadsheet", Browser.Buttons.OK_CANCEL);
if(!CUSTOMER_ID) {
return;
}
// Fetch variable names
// they are column names in the spreadsheet
var sheet = data.getSheets()[0];
var columns = getRowAsArray(sheet, 1);
Logger.log("Processing columns:" + columns);
var customerData = getRowAsArray(sheet, CUSTOMER_ID);
Logger.log("Processing data:" + customerData);
// Assume first column holds the name of the customer
var customerName = customerData[0];
var target = createDuplicateDocument(SOURCE_TEMPLATE, customerName + " agreement");
Logger.log("Created new document:" + target.getId());
for(var i=0; i<columns.length; i++) {
var key = columns[i] + ":";
// We don't replace the whole text, but leave the template text as a label
var text = customerData[i] || ""; // No Javascript undefined
var value = key + " " + text;
replaceParagraph(target, key, value);
}
}

Resources