Calculating GEO transformation params in Vega/d3 - d3.js

Copy this code to https://en.wikipedia.org/wiki/Special:GraphSandbox
The scale and translate parameters of the geo transformation were manually set to match the width & height of the image (see red crosses). How can I make it so that geo transformation matches the entire graph size (or maybe some signal values) automatically, without the manual adjustments?
UPDATE: The translation parameter should have been set to HALF of WIDTH and HEIGHT of the image. See the answer below, and center should have been set to [0,0]. For equirectangular projection, the graph size should have ration 2:1.
{
"version": 2, "width": 800, "height": 400, "padding": 0,
"data": [
{
"name": "data",
"values": [
{"lat":0, "lon":0},
{"lat":90, "lon":-180},
{"lat":-90, "lon":180}
]
}
],
"marks": [
{
"type": "image",
"properties": {
"enter": {
"url": {"value": "wikirawupload:{{filepath:Earthmap1000x500compac.jpg|190}}"},
"width": {"signal": "width"},
"height": {"signal": "height"}
}
}
},
{
"name": "points",
"type": "symbol",
"from": {
"data": "data",
"transform": [{
"type": "geo",
"projection": "equirectangular",
"scale": 127,
"center": [0,0],
"translate": [400,200],
"lon": "lon",
"lat": "lat"
}]
},
"properties": {
"enter": {
"x": {"field": "layout_x"},
"y": {"field": "layout_y"},
"fill": {"value": "#ff0000"},
"size": {"value": 500},
"shape": {"value": "cross"}
}
}
}
]
}

Found an answer (the example above was updated): The "translate" should be set to the center of the image. The "center" on the other hand should be set to [0,0]. The "scale" for the equirectangular projection needs to be set to width/(2*PI)

Related

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/shortflare
full dataset http://myhost:8080/fullflare is served via proxy from https://vega.github.io/vega/data/flare.json
from 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"}
}
}
}
]
}
```
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)

Vega-Lite / Kibana difference to manage URL object

I found an interesting article that used several data models on Vega-Lite. Tabular data were combined by key like in relational databases.
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"title": "Test",
"datasets": {
"stores": [
{"cmdb_id1": 1, "group": "type1"},
{"cmdb_id1": 2, "group": "type1"},
{"cmdb_id1": 3, "group": "type2"}
],
"labelsTimelines": [
{"cmdb_id2": 1, "value": 83},
{"cmdb_id2": 2, "value": 53},
{"cmdb_id2": 3, "value": 23}
]
},
"data": {"name": "stores"},
"transform": [
{
"lookup": "cmdb_id1",
"from": {
"data": {"name": "labelsTimelines"},
"key": "cmdb_id2",
"fields": ["value"]
}
}
],
"mark": "bar",
"encoding": {
"y": {"aggregate": "sum", "field": "value", "type": "quantitative"},
"x": {"field": "group", "type": "ordinal"}
}
}
Vega Editor
The question arose as to whether it was possible to obtain the same result using the construction:
"data": {"url": "...."}
Changed the source for Elasticsearch query:
{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"datasets": {
"stores": [{
"url": {
"%context%": "true"
"index": "test_cmdb"
"body": {
"size": 1000,
"_source": ["cmdb_id", "street","group"]
}
}
format: {property: "hits.hits"}
}]}
"data": {
"name": "stores"
},
"encoding": {
"x": {"field": "url.body.size", "type": "ordinal", "title": "X"},
"y": {"field": "url.body.size", "type": "ordinal", "title": "Y"}
},
"layer": [
{
"mark": "rect",
"encoding": {
"tooltip": [
{"field": "url"}]
}
}
]
}
I understand that there is a syntactical error, the data did not come from Elasticsearch.
Thanks in advance!
example.png
No, it is not currently possible to specify URL data within top-level "datasets". The relevant open feature request in Vega-Lite is here: https://github.com/vega/vega-lite/issues/4004.
Your much better off using Vega rather than Vega-lite for this. In Vega you can specify as many datasets as you like with a URL. For example...
...
data: [
{
name: dataset_1
url: {
...
}
}
{
name: dataset_2
url: {
...
}
}
]
...
This can actually get very interesting since it means you can combine data from multiple indices into one visualisation.
I know this is late, but figured this might help people who are looking around.

Grouped bar-chart in Kibana using Vega-lite

From looking at https://vega.github.io/editor/#/examples/vega-lite/bar_grouped it shows example of creating grouped bar chart from a table of data.
In my case since I am getting data from elasticsearch it is not in tabular form.
I can't figure out a way to create two bar chart for each sum metric on a bucket.
"buckets" : [
{
"key_as_string" : "03/Dec/2019:00:00:00 +0900",
"key" : 1575298800000,
"doc_count" : 11187,
"deploy_agg" : {
"buckets" : {
"deploy_count" : {
"doc_count" : 43
}
}
},
"start_agg" : {
"buckets" : {
"start_count" : {
"doc_count" : 171
}
}
},
"sum_start_agg" : {
"value" : 171.0
},
"sum_deploy_agg" : {
"value" : 43.0
}
},..
I want to create two bars, one representing value of sum_start_agg and another one representing sum_deploy_agg value.
This is what I had for one bar chart.
"encoding": {
"x": {
"field": "key",
"type": "temporal",
"axis": {"title": "DATE"}
},
"y": {
"field": "deploy_agg.buckets.deploy_count.doc_count",
"type": "quantitative",
"axis": {"title": "deploy_count"}
}
"color": {"value": "green"}
"tooltip": [
{
"field": "deploy_agg.buckets.deploy_count.doc_count",
"type": "quantitative",
"title":"value"
}
]
}
You can use the Fold Transform to fold your two columns so that they can be referenced in an encoding. It might look something like this:
{
"data": {
"values": [
{
"key_as_string": "03/Dec/2019:00:00:00 +0900",
"key": 1575298800000,
"doc_count": 11187,
"deploy_agg": {"buckets": {"deploy_count": {"doc_count": 43}}},
"start_agg": {"buckets": {"start_count": {"doc_count": 171}}},
"sum_start_agg": {"value": 171},
"sum_deploy_agg": {"value": 43}
}
]
},
"transform": [
{
"fold": ["sum_start_agg.value", "sum_deploy_agg.value"],
"as": ["entry", "value"]
}
],
"mark": "bar",
"encoding": {
"x": {"field": "entry", "type": "nominal", "axis": null},
"y": {"field": "value", "type": "quantitative"},
"column": {"field": "key", "type": "temporal"},
"color": {"field": "entry", "type": "nominal"}
}
}

How do I sort colour stacks by a specific field in Vegalite in this example?

I'm trying to see how to sort the a bar chart where the color channel is used to encode some information, and in this chart linked below, and well… I'm stumped.
I'm trying to sort the stacked colors by 'yield', so items with the largest yield are at the bottom, but keep the grouping based on 'site' here.
Is this possible with vegalite?
Here's what I would assume would handle the sorting, based on I read in the documentation on sorting, but I'm not having much luck.
"encoding": {
"color": {
"type": "nominal",
"field": "site",
"sort": {
"field":"yield",
"op": "count",
"order": "ascending"
}
},
"x": {"type": "nominal", "field": "variety"},
"y": {"type": "quantitative", "aggregate": "sum", "field": "yield"}
}
What do I need to do to sort a bar chart in this way?
Here's the chart in Vega Editor
You can use the order channel as described at https://vega.github.io/vega-lite/docs/stack.html#order
{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"data": {"url": "data/barley.json"},
"mark": "bar",
"encoding": {
"color": {"type": "nominal", "field": "site"},
"y": {"type": "quantitative", "aggregate": "sum", "field": "yield"},
"order": {"aggregate": "sum", "field": "yield", "type": "quantitative"}
}
}

Bulk geometry ES query

I currently have an ES query to find the nearest location to a lat/long:
GET /geo/_search
{
"sort": [
{
"_geo_distance": {
"geometry": {
"lat": 64,
"lon": 34
},
"order": "asc",
"unit": "mi",
"distance_type": "plane"
}
}
],
"size": 1
}
I want to be able to run this in 1 query for multiple lat/longs, which would return each lat/long related to their nearest location. Is there some way to do this?
GET /geo/_search
{
"sort": [
{
"_geo_distance": {
"geometry": [
{
"lat": 64,
"lon": 34
},
{
"lat": 0,
"lon": 0
}
],
"order": "asc",
"unit": "mi",
"distance_type": "plane"
}
}
],
"size": 1
}
This answer gives more than one point per geo_point. I don't think you can retrieve only the top one per geo_point in one query. You might need to filter the results or to use a loop per each geo_point

Resources