'How to allow AJAX endpoints in mkdocs
Visual is to get this working in mkdocs driven by a local AJAX server.
This one is hard to give an example to but I will. Before I do that, the problem is that I want to use various ajax endpoints to drive Vega visuals in MkDocs. But I run into the CORS permissions.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://machine1:8080/dataflare. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
I have struggled to find documentation on how to solve this so, does anyone know how do we enable this in mkdocs?
The sample is long but this works until you use a local data source other than the vega data. When you change the AJAX endpoint from "url": "https://vega.github.io/vega/data/flare.json" to http://myhost:8080/shortflare (or fullflare endpoint) you get the CORS permission error above.
So should the client mkdocs enable the endpoint as safe cross site source or should bottle AJAX be sending a CORS header? I dont understand why the original AJAX works when the bottle endpoint does not work.
Now the hard part. Showing an example.
This simple bottle server will be the AJAX endpoint mimic of the original flaredata :
sample of data is on
http://myhost:8080/shortflarefull dataset
http://myhost:8080/fullflareis served via proxy fromhttps://vega.github.io/vega/data/flare.jsonfrom bottle import route, run, template import requests DATAFLARE = ''' [ { "id": 1, "name": "flare" }, { "id": 2, "name": "analytics", "parent": 1 }, { "id": 3, "name": "cluster", "parent": 2 }, { "id": 4, "name": "AgglomerativeCluster", "parent": 3, "size": 3938 } ] ''' @route('/shortflare') def getflare(): return DATAFLARE @route('/fullflare') def proxyflare(): return requests.get('https://vega.github.io/vega/data/flare.json').text if __name__ == "__main__": run(host='0.0.0.0', port=8080, debug=True)
mkdocs setup (i.e mkdocs.yml)
site_name: VEGA
dev_addr: '0.0.0.0:2001'
theme:
name: material
nav_style: dark
palette:
accent: pink
primary: lime
plugins:
- search
- charts
markdown_extensions:
- pymdownx.superfences:
custom_fences:
- name: vegalite
class: vegalite
format: !!python/name:mkdocs_charts_plugin.fences.fence_vegalite
extra_javascript:
- https://cdn.jsdelivr.net/npm/vega@5
- https://cdn.jsdelivr.net/npm/vega-lite@5
- https://cdn.jsdelivr.net/npm/vega-embed@6
ve requires
mkdocs==1.2.3
mkdocs-charts-plugin==0.0.6
mkdocs-material==7.3.6
and the markdown to make the vegalite graphic (add this in index.md or anywhere)
Relational maps.
```vegalite
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "An example of Cartesian layouts for a node-link diagram of hierarchical data.",
"width": 600,
"height": 1600,
"padding": 5,
"signals": [
{
"name": "labels", "value": true,
"bind": {"input": "checkbox"}
},
{
"name": "layout", "value": "tidy",
"bind": {"input": "radio", "options": ["tidy", "cluster"]}
},
{
"name": "links", "value": "diagonal",
"bind": {
"input": "select",
"options": ["line", "curve", "diagonal", "orthogonal"]
}
},
{
"name": "separation", "value": false,
"bind": {"input": "checkbox"}
}
],
"data": [
{
"name": "tree",
"url": "https://vega.github.io/vega/data/flare.json",
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "tree",
"method": {"signal": "layout"},
"size": [{"signal": "height"}, {"signal": "width - 100"}],
"separation": {"signal": "separation"},
"as": ["y", "x", "depth", "children"]
}
]
},
{
"name": "links",
"source": "tree",
"transform": [
{ "type": "treelinks" },
{
"type": "linkpath",
"orient": "horizontal",
"shape": {"signal": "links"}
}
]
}
],
"scales": [
{
"name": "color",
"type": "linear",
"range": {"scheme": "magma"},
"domain": {"data": "tree", "field": "depth"},
"zero": true
}
],
"marks": [
{
"type": "path",
"from": {"data": "links"},
"encode": {
"update": {
"path": {"field": "path"},
"stroke": {"value": "#ccc"}
}
}
},
{
"type": "symbol",
"from": {"data": "tree"},
"encode": {
"enter": {
"size": {"value": 100},
"stroke": {"value": "#fff"}
},
"update": {
"x": {"field": "x"},
"y": {"field": "y"},
"fill": {"scale": "color", "field": "depth"}
}
}
},
{
"type": "text",
"from": {"data": "tree"},
"encode": {
"enter": {
"text": {"field": "name"},
"fontSize": {"value": 9},
"baseline": {"value": "middle"}
},
"update": {
"x": {"field": "x"},
"y": {"field": "y"},
"dx": {"signal": "datum.children ? -7 : 7"},
"align": {"signal": "datum.children ? 'right' : 'left'"},
"opacity": {"signal": "labels ? 1 : 0"}
}
}
}
]
}
```
Solution 1:[1]
I actually found out why. The bottle server would need to send the proper header. This is done by adding these few lines to the bottle server.
from bottle_cors_plugin import cors_plugin
from bottle import app
app = app()
app.install(cors_plugin('*'))
if __name__ == "__main__":
run(app=app, host='0.0.0.0', port=8080, debug=True)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
