I have added new dataset to carto Builder using .csv file. But there is null the_geom column. So when i create map using reactjs and carto.js via:
this.cartoClient = new carto.Client({ apiKey: 'key', username: 'user' });
<Map center={center} zoom={zoom} ref={node => { this.nativeMap = node && node.leafletElement }}>
<Basemap attribution="" url={CARTO_BASEMAP} />
<Layer
source={airbnb.source}
style={this.state.layerStyle}
client={this.cartoClient}
hidden={this.state.hidelayers}
/>
</Map>
and using airbnb.source
SELECT
cartodb_id, field_1,field_8, field_7, field_6, field_2, field_4, field_3, field_5,
ST_SetSRID( ST_MakePoint(
field_4,
field_3
),
4326
) AS the_geom,
ST_Transform(ST_Buffer(the_geom,0.001), 3857) as the_geom_webmercator
FROM (SELECT * FROM allreports) AS _camshaft_georeference_long_lat_analysis
Carto.js does not mark points on my map, so i get it clear. How should i workaround the_geom,the_geom_webmercator to get the map with points or the problem is somewhere else?
Does same SQL work in Builder? From where did you get it? Without seeing actual data one can only speculate what can be done, also your field names are not very helpful here. Or is it auto-generated SQL from Builder? I'm not sure if it is good idea to hack around that one, even if it works now, then these internal structures can change anytime. In general there are following scenarios how you get data to map:
Importer tries some heuristics from table structure to add it to map. For example if you have column names latitude and longitude, then the table will automatically geocoded, i.e. geom fields are filled and the table just works. Or if there is column city with English city names, then there is good chance also that it will be on map. So the easiest way is to use these field names, if you already have it in your data.
You can persistently geocode table using Carto SQL API, with something like UPDATE {tablename} SET the_geom = cdb_geocode_namedplace_point({city_column}, {province_column}, {country_column}) in the case of named places, or if you have wgs lat/lon fields then UPDATE {tablename} SET the_geom = st_setsrid(st_point({lon_column}, {lat_column}),4326). This way the the_geom will be filled. To make it sure I would also do UPDATE {tablename} SET the_geom_webercator = st_transform(the_geom, 3857). Of course you can use here st_buffer etc.
you can do also live geocoding query as you seem to try now, just be sure that there is unique cartodb_id, proper the_geom (in wgs84) and the_geom_webmercator (in epsg3857 projection, just as you have). This makes more sense if your data is somehow dynamically updated, otherwise I would do one-time UPDATE to the table.
use Builder geocoding analysis. This creates another 'virtual' live dataset with geocoded data, and this can be used in map view or further analyses. I'm afraid this cannot be done/shown in carto.js maps, this is within Builder only.
p.s. you can find more carto-related posts in https://gis.stackexchange.com/questions/tagged/carto
Related
What's Needed?
I want to get all the restaurants that are near the user's current location (10KM in range).
Description
I have a users table user(Id, Name, Address), here the address is a lat, long string. e.g. 20,21.
2nd table is restaurant(Id, Name, Address), and the format for address is the same as above.
On the front-end I get the current location of the user, and send to the API, and in the API I have a function calling below query from MySQL:
const getAllRestaurants = async (currentAddress: string): Promise<Array<Restaurant>> => {
// query restaurants (using typeorm which will generate something like this)
const rests = "SELECT * FROM restaurant LIMIT 0, 10";
const restsToReturn = [];
// got the restaurants, now filter on based of address
for (const rest of rests) {
// call "isRestaurantInRange" which will return true if the restaurant is user's range
if (isRestaurantInRange(rest.Address, currentAddress)) {
restsToReturn.push(rest);
}
}
return restsToReturn;
}
Drawbacks:
It's SLOW.
The pagination doesn't work as expected, because if 2 out of 10 are in the user's range then we have to manually load up the next data and check the same condition until it reaches 10.
It's a DIRTY way to approach it.
What I am expecting:
Can isRestaurantInRange saved in database (MySQL)? So that when I request the function runs on the database level and return the expected results, without manually filtering it? I am not a MySQL expert, but stored procedure will NOT work as far as I know. Although, there's a caveat with this approach. i.e. I can't call Google Maps Distance API to have exact distance between two points, so need a solution which have google API working.
If you know a TypeORM based solution, it would also be acceptable.
Well, it was suggested to stick with MySQL implementation, which of course doesn't give accurate result. Anyways, I am using following query to get it:
SELECT ST_Distance(ST_GeomFromText('POINT(31.4630941 74.3215482)', 4326 ),
ST_GeomFromText('POINT(31.4780632 74.3125699)', 4326 ),
'kilometre') AS distance;
Used this link to verify that the MySQL function gives correct STRAIGHT distance between two points.
This is a great article about spatial data in MySQL. Quoting:
These are two of the most used SRSs. SRID 4326 is GPS coordinates.
If you use a SPATIAL index with InnoDB, you need MySQL 5.7.6 (or newer) to also get SP_Distance_Sphere().
Do store the actual POINTs in the table; that is, don't compute them on the fly since that is likely to prevent the use of the index.
For other tips, see http://mysql.rjweb.org/doc.php/find_nearest_in_mysql
There may be a disadvantage in splitting into 2 tables. Please provide SHOW CREATE TABLE.
As "collection group query" is still not implemented on Firestore I am using a map of values as a workaround. Here is the structure:
/chat/[room_id]/
user[ user_id ] = true
The query is something like:
db.collection( 'chat' )
.doc( room_id )
.where( 'user.' + user_id, "==", true )
.onSnapshot( ... )
They query works perfectly, but if a "user-map" adds or remove the "user_id" field, the listener (onSnapshot) is not called. On Firebase console the value flashes indicating that a change was made.
According to the documentation maps are automatically indexed, so it should not be a indices problem.
Any idea?
Looking at the documentation we can see that:
Queries on multiple fields with range filters require a composite
index. Unfortunately, this is not possible with the approach shown
above. Indexes must be defined on specific field paths. You would have
to create an index on each possible field path (such as
categories.cats or categories.opinion) which is impossible to do in
advance if your categories are user generated.
The "approach shown above" refers to the case where you are performing a compound query with a map of values (same example as yours). The solution they propose is to
encode all of the information for the query into the map values
Although not ideal, it might be useful for certain cases.
The Google Maps Places Autocomplete does not work as expected anymore.
https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete
When inserting a search string in the map (for example "ZKM"), it will give some recommendations in the drop down list. In this case it will be "ZKM | Zentrum für Kunst und Medientechnologie Karlsruhe, Lorenzstraße, Karlsruhe, Deutschland". When clicking this item, no marker will be placed on the map!
But when searching for "Karlsruhe" and clicking the first search result "Karlsruhe, Deutschland" the marker is placed correctly.
In the code a function called getPlace() ist called.
var place = autocomplete.getPlace();
The place should contain an object "geometry", but it does not.
Is there any workaround for this problem?
Please be sure you set 'geometry' field in autocomplete like this:
autocomplete.setFields(['address_component', 'geometry']);
Take a look at the beginning of the function:
if (!place.geometry) {
return;
}
A PlaceResult may, but must not have a geometry-property.
To clarify how the autocomplete works:
when you type something, the API will request the predictions(to populate the dropdown). Only when you select a place from the dropdown it requests the data(including the geometry) for the particular place.
Obviously there are inconsistencies of the used data(the API shouldn't suggest a place where no informations are accessible), but that's how it is, it may happen that you get a prediction without a place.
Workaround: AFAIK no
Looks like it has been fixed by Google :)
Yes, the place contains an object "geometry".
To find this, you should use this :
autocomplete.getPlace().geometry.location.lat() //for the latitude
autocomplete.getPlace().geometry.location.lng() //for the longitude
I'm looking to make a fusion layer that allows user to select at least two markers at the same time in order to display a direct comparison of that data using charts.
I've been searching the Google Maps API and sample code section but I can't find any examples of when this has been implemeneted thus I'm at a bit of a loose end trying to do it.
Has anyone ever come across something like this or know if it's possible?
It's possible, when you click on a feature you'll receive the data for the feature, you only need to collect the data returned multiple clicks(e.g. in an array ) and build the query based on these data.
For the linked example the important row is the "County"-row, it will be used to filter the results. To get results for multiple counties us a IN()-condition.
the modified drawVisualization-function may look like this:
//counties may either be
//a string(a single county)
//or an array(1 or more counties)
function drawVisualization(counties) {
counties=(typeof counties==='string')?[counties]:counties;
google.visualization.drawChart({
"containerId": "visualization",
"dataSourceUrl": "http://www.google.com/fusiontables/gvizdata?tq=",
"query": "SELECT County,'2010' FROM 1761814 WHERE County IN('"+counties.join("','")+"') and Sector='Total'",
"chartType": "ColumnChart",
"options": {
"title": 'comparision',
"height": 400,
"width": 400
}
});
}
To be able to choose between single/multi-selection there may be many ways. You may e.g. use the CTRL-key to enable the multi-selection. Set a flag when the key is pressed, when the flag is set push the new County to the array, when not create a new array with the given County
I'm attempting to create a dynamic map using the latest Google Map API. Everything is going smooth so far. I do have a question of course:
How would I/you go about saving my current map?
Let's say you build a map with dynamic markers: Since everything is done via JavaScript, I need to get/set those values from a file/database.
I was thinking about outputting the entire google.map.Markers as a JSON and send it to a database as a string, but then if I have around 100 places, I'm not sure how well it would go and I'm worried about efficiency.
Is this the only way to do it and am I thinking properly? Basically your website users are allowed to place a marker on the map, which then are subject to confirmation of course. Once it's confirmed, that marker must be in the latest "version" of the map, so I must get that info from/into a database/file.
Thanks in advance!
I'm creating similar application and I implemented it this way:
I have a Marker table which has columns for each attribute that I'm using in markers (e.g. latitude, longitude, name, description, type, etc.) When someone adds a marker I'm just saving the attributes of the marker to the database. Next time I want to show the marker I'm just getting the attributes from database, encode them to JSON and attach to the page. Inside page I have the JS that grabs those attributes and creates the markers inside the map. Pseudocode:
//this is generated dynamically from DB.
var markers = [
{lat:115416,lng:26411},
{lat:115416,lng:26411}
];
//this is static, just grabs the dynamic bit and puts it on the map:
for (var i = 0; i < markers.length; i++){
//creates a marker object
var marker = new Marker({lat:markers[i].lat, lng:markers[i].lng })
//displays it on the map
map.addMarker(marker);
}
the benefit of this is that your data in the database is independent from map implementation, e.g. if in the future you decide to move to apple maps and it has different implementation you can just write different JS to handle the data. Also you can query over it, e.g. you can query for places that are close by looking at lat and lang, etc..