I am working on building out a simple web map in Folium that adds the functionality of a Mapbox geocoder to the index.html file that is generated from my map script. From what I can find, I don't see any way to add a geocoder directly in my Python script (which uses the Folium library), so this seems just about the only way to accomplish this.
I've looked at Mapbox's documentation, and while I'm very new to Javascript, I'm hoping that I can just copy & paste pieces of the Javascript in the referenced documentation directly into the index.html file that's spit out.
Here's my Python script that initially creates the map in Folium. It only contains a single marker in downtown Atlanta with a Layer Control box in the top-left corner of the map. For the sake of brevity, I've made this map as practically stripped down as possible:
# dependencies
import folium
# Declare map variable
m = folium.Map(location=[33.756290532017985, -84.39698869622109],
tiles=None,
zoom_start=11,
zoom_control=False)
# Mapbox street layer
folium.TileLayer(
tiles = 'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}#2x?access_token=pk.eyJ1Ijoid3dyaWdodDIxIiwiYSI6ImNsNmNnbW92cjF3YXczY281NXRua25xMHgifQ.1Xa_wr0DUhuoNGP0Cbe5Kg',
attr = 'Mapbox',
name = 'Streets',
overlay = False,
control = True,
show = True,
min_zoom = 11,
max_zoom = 30
).add_to(m)
# Add marker in Atlanta
folium.Marker([33.74908343904121, -84.38812827298649]).add_to(m)
# Add in layer control
folium.LayerControl(position='topleft').add_to(m)
m.save("../index.html")
The resulting index.html (when opened in VSCode) looks very ugly. To my eyes, it's practically unreadable but nevertheless reproduced here:
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script>
L_NO_TOUCH = false;
L_DISABLE_3D = false;
</script>
<style>html, body {width: 100%;height: 100%;margin: 0;padding: 0;}</style>
<style>#map {position:absolute;top:0;bottom:0;right:0;left:0;}</style>
<script src="https://cdn.jsdelivr.net/npm/leaflet#1.6.0/dist/leaflet.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet#1.6.0/dist/leaflet.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css"/>
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_c8f6a7d59d7e0d75d463b5df65347ca6 {
position: relative;
width: 100.0%;
height: 100.0%;
left: 0.0%;
top: 0.0%;
}
</style>
</head>
<body>
<div class="folium-map" id="map_c8f6a7d59d7e0d75d463b5df65347ca6" ></div>
</body>
<script>
var map_c8f6a7d59d7e0d75d463b5df65347ca6 = L.map(
"map_c8f6a7d59d7e0d75d463b5df65347ca6",
{
center: [33.756290532017985, -84.39698869622109],
crs: L.CRS.EPSG3857,
zoom: 11,
zoomControl: false,
preferCanvas: false,
}
);
var tile_layer_57433496d1534b262b2ead21a58cd5f2 = L.tileLayer(
"https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/{z}/{x}/{y}#2x?access_token=pk.eyJ1Ijoid3dyaWdodDIxIiwiYSI6ImNsNmNnbW92cjF3YXczY281NXRua25xMHgifQ.1Xa_wr0DUhuoNGP0Cbe5Kg",
{"attribution": "Mapbox", "detectRetina": false, "maxNativeZoom": 30, "maxZoom": 30, "minZoom": 11, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
).addTo(map_c8f6a7d59d7e0d75d463b5df65347ca6);
var marker_c56903aa791d9f42199fb8edd7fbf18e = L.marker(
[33.74908343904121, -84.38812827298649],
{}
).addTo(map_c8f6a7d59d7e0d75d463b5df65347ca6);
var layer_control_31fb53235cbe88479bc47b285b10ca9c = {
base_layers : {
"Streets" : tile_layer_57433496d1534b262b2ead21a58cd5f2,
},
overlays : {
},
};
L.control.layers(
layer_control_31fb53235cbe88479bc47b285b10ca9c.base_layers,
layer_control_31fb53235cbe88479bc47b285b10ca9c.overlays,
{"autoZIndex": true, "collapsed": true, "position": "topleft"}
).addTo(map_c8f6a7d59d7e0d75d463b5df65347ca6);
</script>
Once I get to this step, I've tried nearly every possible combination of copy/pasting in the various bits of JS from the Mapbox geocoder documentation (referenced at the beginning of this post), but I'm not sure where exactly it goes or if this is even possible to do. I've made sure to properly change all the necessary references to the map object once I copy it over, but I can't get it working properly. That is, I can't get the index.html file that is generated from my Python script to correctly show an autofill geocoder box (similar to what you get with Google Maps). The error that I get most often from my browser console is RangeError: Maximum call stack size exceeded
Is it even possible to "add in" a Mapbox geocoder to a Folium map that's built in a Python environment? If not, is there a better way to build out a Folium map in Python but still manage to incorporate some of the really cool Mapbox features, like the geocoder?
You can't do what you're trying to do.
Folium generates code for Mapbox.js, which is based on Leaflet.
Mapbox-GL-Geocoder, as its name suggests, works with Mapbox GL JS.
Different, incompatible libraries.
Related
I'm trying to get some Google Ads to play nice. Basically, we have some inline ads that we display between listings:
<div class="listing-ad" id="ad<%row_num%>">
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-1210636681400112"
data-ad-slot="2068176827"
data-ad-format="horizontal"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
These work ok. We load the Google scripts in requireJS using:
"google_ads": "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1210636681400112",
We now want to include an "anchor" ad at the bottom of the page. As per the article ( https://support.google.com/adsense/answer/7478225?hl=en ), I'm adding this near the end of my page:
(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: "ca-pub-1210636681400112",
enable_page_level_ads: true,
overlays: {bottom: true}
});
When running their example, the ad shows but I get:
{ message: "adsbygoogle.push() error: Only one 'enable_page_level_ads' allowed per page.",
If I comment out enable_page_level_ads: true, the ad still shows (but not at the bottom), and I then get a new error message:
message: "adsbygoogle.push() error: All ins elements in the DOM with
class=adsbygoogle already have ads in them.",
I'm at my witts end as to what else to try. I guess ideally, I'd like an <ins> HTML option where I can pass data-ad-overlays="bottom" as an option (vs doing it as a <script>).
I've even tried passing the options via:
(adsbygoogle = window.adsbygoogle || []).push({ google_ad_client: "ca-pub-1210636681400112", enable_page_level_ads: true, overlays: { bottom: true } })
Yet still no joy.
Is this possible? Am I missing something stupid? I feel like I've been chasing my tail on this for hours now!
Bottom anchor ads aren't well supported today. There is no good way to force them as top anchors are default and AdSense frontend doesn't provide way to switch to bottom. The article you provided is outdated and needs to be revamped or more likely removed. But if you do want to force bottom anchors you can try the following snippet:
<head>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: "ca-pub-1234567891234567",
enable_page_level_ads: true,
overlays: {bottom: true}
});
</script>
</head>
Note that web property id is no longer present in the tag and that makes the difference. Though by removing web property id you might miss on some other optimizations.
I have a problem I do not know how to solve, I do not know if it's a bug of 'azure media player' but when I view a streaming video shows me this error "'Uncaught Error: cannot find the request in the request queue azuremediaplayer.min.js (2,338210)' but if I see a local video as a mp4 does not give me any problems. What could be the problem? Excuse my English.
By the way, I'm using Ripple to emulate Android, if I visualize from a physical device does not give me problems.
Thanks
(function () {
"use strict";
document.addEventListener('deviceready', onDeviceReady.bind(this), false);
var myOptions = {
"nativeControlsForTouch": false,
controls: false,
autoplay: false,
width: "640px",
height: "360px",
poster: "",
logo: {
enabled: false
}
}
var myPlayer = amp("azuremediaplayer", myOptions);
function onDeviceReady() {
// Handle the Cordova pause and resume events
document.addEventListener( 'pause', onPause.bind( this ), false );
document.addEventListener( 'resume', onResume.bind( this ), false );
// TODO: Cordova has been loaded. Perform any initialization that requires Cordova here.
//var element = document.getElementById("deviceready");
//element.innerHTML = 'Device Ready';
//element.className += ' ready';
myPlayer.src([
{
//"src": "movie/Rutina.mp4",
//"type": "video/mp4"
"src": "http://amssamples.streaming.mediaservices.windows.net/830584f8-f0c8-4e41-968b-6538b9380aa5/TearsOfSteelTeaser.ism/manifest",
"type": "application/vnd.ms-sstr+xml",
"protectionInfo": [
{
"type": "AES",
"authenticationToken": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cm46bWljcm9zb2Z0OmF6dXJlOm1lZGlhc2VydmljZXM6Y29udGVudGtleWlkZW50aWZpZXIiOiI5ZGRhMGJjYy01NmZiLTQxNDMtOWQzMi0zYWI5Y2M2ZWE4MGIiLCJpc3MiOiJodHRwOi8vdGVzdGFjcy5jb20vIiwiYXVkIjoidXJuOnRlc3QiLCJleHAiOjE3MTA4MDczODl9.lJXm5hmkp5ArRIAHqVJGefW2bcTzd91iZphoKDwa6w8"
}
]
}
]);
myPlayer.autoplay(true);
};
function onPause() {
// TODO: This application has been suspended. Save application state here.
};
function onResume() {
// TODO: This application has been reactivated. Restore application state here.
};
} )();
<!DOCTYPE html>
<html>
<head>
<!--
Customize the content security policy in the meta tag below as needed. Add 'unsafe-inline' to default-src to enable inline JavaScript.
For details, see http://go.microsoft.com/fwlink/?LinkID=617521
-->
<meta http-equiv="Content-Security-Policy" content="default-src http://amp.azure.net 'self' data: gap: blob: https://ssl.gstatic.com http://amssamples.streaming.mediaservices.windows.net 'unsafe-eval'; style-src 'self' 'unsafe-inline'; connect-src 'self'; media-src http://localhost:4400/ blob:">
<title>Mobile</title>
<link href="lib/ionic/release/css/ionic.css" rel="stylesheet" />
<link href="http://amp.azure.net/libs/amp/1.6.3/skins/amp-default/azuremediaplayer.min.css" rel="stylesheet" />
<script src="http://amp.azure.net/libs/amp/1.6.3/azuremediaplayer.min.js"></script>
</head>
<body>
<video id="azuremediaplayer" class="azuremediaplayer amp-default-skin amp-big-play-centered"></video>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="scripts/platformOverrides.js"></script>
<script src="lib/ionic/release/js/ionic.bundle.js"></script>
<script src="scripts/index.js"></script>
</body>
</html>
Unfortunately, using an emulator for video playback can be an unreliable testing scenario. The issue you're seeing could very well be unique to the emulator itself, which can be dependent on the performance of the machine your emulator is running on as well as the capabilities of the emulator.
You are better of testing your code on a physical device, especially if the issue is not occurring on it.
I tried to acquaint myself with extending SAPUI5 Applications. To do this I used the splitapp in the folder test-resources/sap/m/demokit
As specified in the Developer Guide - Extending SAPUI5 Applications you only have to create the Component.js for a the custom application project. Now there are 2 questions:
How can you bootstrap the extended Application without having a index.html?
How do you solve relative path-problems (e.g inside the function createContent)?
My current solution is to copy the index.html from the splitapp, paste it into splittapp-ext and modify all the paths...but this solution doesn't seems to be very modular:
original index.html (splitapp):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
<meta charset="UTF-8">
<title>'sap.m.SplitApp' Demo Application</title>
<script id='sap-ui-bootstrap' type='text/javascript'
src='../lib/openui5/resources/sap-ui-core.js'
data-sap-ui-theme='sap_bluecrystal'
data-sap-ui-libs='sap.m'
data-sap-ui-resourceroots='{
"res": "./",
"sap.ui.demo.splitapp" : "./",
"view" : "./view",
"model" : "./model",
"util" : "./util"
}' >
</script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script>
new sap.m.Shell("Shell", {
title : "sap.m splitapp",
showLogout : false,
app : new sap.ui.core.ComponentContainer({
name : 'sap.ui.demo.splitapp'
}),
homeIcon : {
'phone' : 'img/57_iPhone_Desktop_Launch.png',
'phone#2' : 'img/114_iPhone-Retina_Web_Clip.png',
'tablet' : 'img/72_iPad_Desktop_Launch.png',
'tablet#2' : 'img/144_iPad_Retina_Web_Clip.png',
'favicon' : 'img/favicon.ico',
'precomposed': false
}
}).placeAt('content');
</script>
</head>
<body class='sapUiBody' id="content">
</body>
</html>
modified index.html (splitapp-ext):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
<meta charset="UTF-8">
<title>'sap.m.SplitApp' Demo Application</title>
<script id='sap-ui-bootstrap' type='text/javascript'
src='../lib/openui5/resources/sap-ui-core.js'
data-sap-ui-theme='sap_bluecrystal'
data-sap-ui-libs='sap.m'
data-sap-ui-resourceroots='{
"res": "../splitapp",
"sap.ui.demo.splitapp" : "../splitapp",
"view" : "../splitapp/view",
"model" : "../splitapp/model",
"util" : "../splitapp/util"
}' >
</script>
<link rel="stylesheet" type="text/css" href="../splitapp/css/style.css">
<script>
new sap.m.Shell("Shell", {
title : "sap.m splitapp",
showLogout : false,
app : new sap.ui.core.ComponentContainer({
name : 'sap.ui.demo.splitapp'
}),
homeIcon : {
'phone' : 'img/57_iPhone_Desktop_Launch.png',
'phone#2' : 'img/114_iPhone-Retina_Web_Clip.png',
'tablet' : 'img/72_iPad_Desktop_Launch.png',
'tablet#2' : 'img/144_iPad_Retina_Web_Clip.png',
'favicon' : 'img/favicon.ico',
'precomposed': false
}
}).placeAt('content');
</script>
</head>
<body class='sapUiBody' id="content">
</body>
</html>
For the 2. question I do not have a modular solution.
The anonymous function createContent inside Component.js of the splitapp defines a relative path to the JSON-models. The models cant't be found inside the splitapp-ext Application. The only way I found is to modify the Component.js:
createContent : function () {
// create root view
var oView = sap.ui.view({
id : "app",
viewName : "view.App",
type : "JS",
viewData : { component : this }
});
// --> WORKAROUND: add the module path to the JSON-paths
var rootPath = jQuery.sap.getModulePath("sap.ui.demo.splitapp");
// set navigation model
// load the global data model
var oJSONDataModel = new sap.ui.model.json.JSONModel(rootPath + "/model/data.json");
oView.setModel(oJSONDataModel);
// load the global image source model
var oImgModel = new sap.ui.model.json.JSONModel(rootPath + "/model/img.json");
oView.setModel(oImgModel, "img");
// done
return oView;
}
Is there a better way to extend a SAPUI5 Application?
You can try the extension of an app using SAP Web IDE . You can find the trial links on SAP SCN . The whole idea of Component based approach is to enable the applications to be launched in a broader context such as a Fiori Launchpad . If you want to test it locally, you might consider setting up a local launchpad sandbo from this link:
Set up local Fiori Launchpad.
It is possible to run a local test version of launchpad (with limitations).
first three search results
detailed wiki
As for the second question, remember that control is looking for a model matching the bind path inside on itself, later on parents, and bubbling up to the core. So, setting a model to one view is not best option. You can set model directly to the Component.js as whole application have access there, or just for testing, to the core - sap.ui.getCore().setModel(myModel).
This is an example from ui documentation of proper definition of Component.js with assigned models (for version 1.30, for previous ones you probably won't use 'define'):
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel",
"sap/ui/model/resource/ResourceModel"
], function (UIComponent, JSONModel, ResourceModel) {
"use strict";
return UIComponent.extend("sap.ui.demo.wt.Component", {
metadata : {
manifest: "json"
},
init : function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
recipient : {
name : "World"
}
};
var oModel = new JSONModel(oData);
this.setModel(oModel);
// set i18n model
var i18nModel = new ResourceModel({
bundleName : "sap.ui.demo.wt.i18n.i18n"
});
this.setModel(i18nModel, "i18n");
}
});
});
Similar sample documented in openui5 you can find here:
component and model sample
I'm looking to create a grouped column chart in Highcharts, except with multiple groups in a given day. The graph would look like this http://www.highcharts.com/demo/column-stacked-and-grouped (from this forum question http://highslide.com/forum/viewtopic.php?f=9&t=19575), except with each stacked bar replaced with a grouped set of columns (non-stacked). We would therefore see multiple groups of columns per day, the idea being that each group corresponds to one user. Does anyone know how to do this?
edit: Here's a jsfiddle I've found http://jsfiddle.net/pMA2H/1/
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>ElementStacks - jsFiddle demo</title>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.4.2.js'></script>
<link rel="stylesheet" type="text/css" href="/css/normalize.css"/>
<link rel="stylesheet" type="text/css" href="/css/result-light.css"/>
<script type='text/javascript' src="http://highcharts.com/js/testing.js"></script>
<style type='text/css'>
</style>
<script type='text/javascript'>//<![CDATA[
$(function(){
/*
Data is:
Gross Amount Cost Amount
Services Australia 20 10
Germany 30 15
Manufacturing Australia 35 17
Germany 25 12
----
Would like to be able define my categories hierarchically - example:
xAxis: [{
categories: [{
name: 'Services'
children: ['Australia', 'Germany']
},{
name: 'Manufacturing'
children: ['Australia', 'Germany']
}]
}]
and get a result similar to what is fudged up by using the renderer on the right.
*/
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'column'
},
xAxis: [{
categories: ['Australia', 'Germany', 'Australia', 'Germany'],
labels: {
y: 40
}
}],
legend: {
margin: 40
},
series: [{
name: 'Gross',
data: [['Services', 20],['Services',30],['Manufacturing', 35],['Manufacturing', 25]]
},{
name: 'Cost',
data: [['Services', 10],['Services',15],['Manufacturing', 17],['Manufacturing', 13]]
}]
}, function(chart){
$('.highcharts-axis:first > text').each(function() {
this.setAttribute('y', parseInt(this.getAttribute('y')) - 20)
});
var text1 = chart.renderer.text("Services", 150, 340).add();
var text2 = chart.renderer.text("Manufacturing", 350, 340).add();
});
});//]]>
</script>
</head>
<body>
<div id="container" style="height: 400px; width: 500px"></div>
</body>
</html>
from the thread here http://highcharts.uservoice.com/forums/55896-general/suggestions/2230615-grouped-x-axis#comments. The code for the x-axis increments is a bit tedious though, because you have to manually add each increment and include its spacing to make sure your data points line up. I've done graphs previously where you can instead specify a pointStart and pointInterval for dates. If someone knows of a more elegant solution, that'd be great.
You can use plugin for grouped categories, here you can find it: https://github.com/blacklabel/grouped_categories
Unless there is something else you are not explaining, what you are asking for is the default behavior of a grouped column chart:
http://jsfiddle.net/jlbriggs/TfvGp/
.
all that is required to achieve this is multiple data series and a type of 'column'
I had the same problem, and solved it usign plain HighCharts. It needs some magical datashuffling, but the result is fair.
See here: https://stackoverflow.com/a/31029535/461499
To solve this problem, u need to stack on a variable that can't stack. Like:
series :{
{
name: 'boys',
stack: 1,
data: [2, 6, 5,0]
}
{
name: 'girls',
stack: 2,
data: [0, 6, 1,3]
}
}
No stacking with 1,2,3,4 e.t.c
I'm running Sinatra with Backbone.js. I'm trying to split up my models, views, etc so they aren't all lumped into a single JS file. Right now I have the following.
index.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<script src="scripts/underscore-min.js"></script>
<script src="scripts/jquery-1.5.min.js"></script>
<script src="scripts/backbone-min.js"></script>
<script src="scripts/models.js"></script>
...
models.js
Models = {
var Event = Backbone.Model.extend({
});
var Events = Backbone.Collection.extend({
url: '/events',
model: Event
});
};
So models.js expects that Backbone.js has been loaded, which it should have been based on index.html, however, I'm getting a JavaScript error in models.js where I reference Backbone.Model.
Any ideas on what I'm missing here?
That isn't valid javascript. Something like this is more likely to work :
Models = {}
Models.Event = Backbone.Model.extend({
});
Models.Events = Backbone.Collection.extend({
url: '/events',
model: Event
});