Vegalite: pie chart not aggregating together - vega-lite

I have a json date values that I'm adding to the vega-lite for visualization in pie chart. The legends seem to render properly (there's 2 distinct legends for 2020 q3 and 2020 q4). But the pie chart itself doesn't seem to aggregate together. How would I make sure that all the 2020Q4 are grouping together? How do I fix my spec??
pie chart with no aggregation for same data
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 880,
"height": 376,
"config": {
"range": {
"category": {
"scheme": "tableau20"
}
},
"legend": {
"labelColor": "#333",
"labelFontSize": 11,
"symbolSize": 30,
"symbolType": "circle",
"symbolStrokeWidth": 0,
"titleColor": "#333",
"titleFontSize": 14,
"titlePadding": 10,
"titleFontWeight": 500
},
"autosize": {
"type": "fit",
"contains": "padding"
},
"font": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\"",
"axisLeft": {
"labelFontSize": 14,
"labelColor": "#333",
"labelLimit": 180,
"titleFontSize": 16,
"titleLimit": 180
},
"style": {
"label": {
"align": "left",
"baseline": "middle",
"dx": 4
},
"cell": {
"stroke": "transparent"
}
}
},
"layer": [
{
"mark": {
"type": "arc",
"innerRadius": {
"expr": "min(width,height)/5"
},
"outerRadius": {
"expr": "min(width,height)/4"
},
"tooltip": true,
"padAngle": 0.01
},
"params": [
{
"name": "highlight",
"select": {
"type": "point",
"on": "mouseover"
}
},
{
"name": "select",
"select": "point"
}
]
},
{
"mark": {
"type": "text",
"radius": {
"expr": "min(width,height)/4+min(width,height)/5/2"
},
"stroke": "#666666",
"limit": {
"expr": "min(width,height)/5"
}
},
"encoding": {
"text": {
"field": "color",
"title": "Due date",
"type": "nominal",
"timeUnit": "yearquarter"
}
}
}
],
"encoding": {
"color": {
"field": "color",
"title": "Due date",
"type": "nominal",
"timeUnit": "yearquarter"
},
"theta": {
"field": "thetaAggregated",
"type": "quantitative",
"title": "Values",
"stack": true
},
"fillOpacity": {
"condition": [
{
"param": "select",
"value": 1
}
],
"value": 0.3
}
},
"transform": [
{
"calculate": "datetime(datum.color.year, datum.color.month, datum.color.date)",
"as": "color"
},
{
"joinaggregate": [
{
"op": "count",
"field": "theta",
"as": "thetaAggregated"
}
],
"groupby": [
"color"
]
}
],
"data": {
"values": [
{
"color": {
"year": 2020,
"month": 9,
"date": 30,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "rec79Wjae6P45XNpl"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 20,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recrQaNcIH4wueWrT"
},
{
"color": {
"year": 2020,
"month": 8,
"date": 29,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recwVzB5CNu0E6x9J"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 25,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recp8FrOTOgSqQlxV"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 5,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recpgd5QYGyHPz6oC"
},
{
"color": {
"year": 2020,
"month": 10,
"date": 7,
"hours": 16,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recerFXuq7ply21Ba"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 18,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recNfz0B2qasVXfwS"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 12,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recriiVtRVuueAwTP"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 19,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recbGumPg7L28cUrh"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 26,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recrhgU6BXOBYY8F4"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 31,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recJzAP0NPlzck0aa"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 32,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "rec2spYZGJTOnq32F"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 17,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recldmzqvJhcZ9oqy"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 25,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recegvuNEeNoSyyMT"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 4,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recDwkAeTWQ9KzDXS"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 9,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recKTwDYDpXsKAiAC"
}
]
}
}

Instead of joinaggregate, you can use aggregate transform as it will help you to generate new data set which you can utilize for the values pie chart. Simply convert the color values using calculate and expressions and then perform aggregation.
Below is the code snippet or refer editor:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 880,
"height": 376,
"config": {
"range": {"category": {"scheme": "tableau20"}},
"legend": {
"labelColor": "#333",
"labelFontSize": 11,
"symbolSize": 30,
"symbolType": "circle",
"symbolStrokeWidth": 0,
"titleColor": "#333",
"titleFontSize": 14,
"titlePadding": 10,
"titleFontWeight": 500
},
"autosize": {"type": "fit", "contains": "padding"},
"font": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\"",
"axisLeft": {
"labelFontSize": 14,
"labelColor": "#333",
"labelLimit": 180,
"titleFontSize": 16,
"titleLimit": 180
},
"style": {
"label": {"align": "left", "baseline": "middle", "dx": 4},
"cell": {"stroke": "transparent"}
}
},
"layer": [
{
"mark": {
"type": "arc",
"innerRadius": {"expr": "min(width,height)/5"},
"outerRadius": {"expr": "min(width,height)/4"},
"tooltip": true,
"padAngle": 0.01
},
"params": [
{"name": "highlight", "select": {"type": "point", "on": "mouseover"}},
{"name": "select", "select": "point"}
]
},
{
"mark": {
"type": "text",
"stroke": "#666666",
"radius": {"expr": "min(width,height)/4+min(width,height)/5/2"},
"limit": {"expr": "min(width,height)/5"}
},
"encoding": {
"text": {"field": "quarterTime", "title": "Due date", "type": "nominal"}
}
}
],
"encoding": {
"color": {"field": "quarterTime", "title": "Due date", "type": "nominal"},
"theta": {
"field": "thetaAggregated",
"type": "quantitative",
"title": "Values",
"stack": true
},
"fillOpacity": {
"condition": [{"param": "select", "value": 1}],
"value": 0.3
}
},
"transform": [
{
"calculate": "datetime(datum.color.year, datum.color.month, datum.color.date)",
"as": "color"
},
{"calculate": "timeFormat(datum.color,'%Y Q%q')", "as": "quarterTime"},
{
"aggregate": [{"op": "count", "field": "theta", "as": "thetaAggregated"}],
"groupby": ["quarterTime"]
}
],
"data": {
"values": [
{
"color": {
"year": 2020,
"month": 9,
"date": 30,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "rec79Wjae6P45XNpl"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 20,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recrQaNcIH4wueWrT"
},
{
"color": {
"year": 2020,
"month": 8,
"date": 29,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recwVzB5CNu0E6x9J"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 25,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recp8FrOTOgSqQlxV"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 5,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recpgd5QYGyHPz6oC"
},
{
"color": {
"year": 2020,
"month": 10,
"date": 7,
"hours": 16,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recerFXuq7ply21Ba"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 18,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recNfz0B2qasVXfwS"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 12,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recriiVtRVuueAwTP"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 19,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recbGumPg7L28cUrh"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 26,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recrhgU6BXOBYY8F4"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 31,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recJzAP0NPlzck0aa"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 32,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "rec2spYZGJTOnq32F"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 17,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recldmzqvJhcZ9oqy"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 25,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recegvuNEeNoSyyMT"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 4,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recDwkAeTWQ9KzDXS"
},
{
"color": {
"year": 2020,
"month": 9,
"date": 9,
"hours": 17,
"minutes": 0,
"seconds": 0,
"milliseconds": 0
},
"theta": "recKTwDYDpXsKAiAC"
}
]
}
}

Related

vega lite - persist null date/time in chart

How do I persist the null in the data on visualization with vega chart while rendering the date/time for data the timestamp. Right now, it looks like null data is getting passed as default time of 04:00
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{
"x": null,
"y": "recoPU8F3Asuc8t3n"
},
{
"x": "2017-06-02T07:00:00.000Z",
"y": "reco056sZzsAd7qVp"
},
{
"x": null,
"y": "reclQZbw7CiAegm1f"
},
{
"x": "2017-07-14T07:00:00.000Z",
"y": "recAzUhUdekIdkSVt"
},
{
"x": null,
"y": "rec0NHCpaRDP9W1pd"
},
{
"x": null,
"y": "recPYz3QNpXgrmBVy"
}
]
},
"config": {
"range": {
"category": [
"#46bfdd"
]
},
"legend": {
"disable": false,
"labelColor": "#333",
"labelFontSize": 11,
"symbolSize": 30,
"rowPadding": 4,
"symbolType": "circle",
"symbolStrokeWidth": 0,
"titleColor": "#666666",
"titleFontSize": 11,
"titlePadding": 10,
"titleFontWeight": 500,
"orient": "right"
},
"axisY": {
"tickMinStep": 1,
"format": "~s",
"formatType": "number"
},
"axis": {
"domainColor": "#E8E8E8",
"gridColor": "#E8E8E8",
"tickColor": "#E8E8E8",
"grid": true,
"gridWidth": 1,
"labelColor": "#666666",
"labelFontSize": 11,
"labelLimit": 180,
"titleColor": "#999999",
"tickSize": 16,
"titleFontSize": 13,
"titlePadding": 10,
"titleFontWeight": 400,
"labelPadding": 4,
"titleLimit": 180
},
"autosize": {
"type": "fit",
"contains": "padding"
},
"axisLeft": {
"labelFontSize": 11,
"labelColor": "#999999",
"labelLimit": 180,
"titleFontSize": 13,
"titleFontWeight": 400,
"titleLimit": 180
},
"style": {
"label": {
"align": "left",
"baseline": "middle",
"dx": 4
},
"cell": {
"stroke": "transparent"
}
}
},
"mark": {
"type": "bar",
"width": {
"band": 0.7
},
"tooltip": true,
"cornerRadiusEnd": 3,
"cursor": "pointer",
"color": "#4787cd"
},
"params": [
{
"name": "highlight",
"select": {
"type": "point",
"on": "mouseover"
}
},
{
"name": "select",
"select": "point"
}
],
"encoding": {
"x": {
"field": "x",
"type": "nominal",
"axis": {
"labelAngle": -90,
"format": "%I:%M",
"formatType": "time",
"title": "Reservation On"
},
"sort": {
"encoding": "x",
"order": "ascending"
},
"timeUnit": "hoursminutes"
},
"y": {
"field": "y",
"type": "quantitative",
"aggregate": "count",
"axis": {
"title": "Number of records"
}
},
"tooltip": [
{
"field": "x",
"title": "Reservation On",
"format": "%I:%M",
"formatType": "time",
"timeUnit": "hoursminutes"
},
{
"field": "y",
"type": "quantitative",
"aggregate": "count",
"title": "Number of records"
}
],
"fillOpacity": {
"condition": [
{
"param": "select",
"value": 1
}
],
"value": 0.3
},
"strokeWidth": {
"condition": [
{
"param": "select",
"empty": false,
"value": 2
},
{
"param": "highlight",
"empty": false,
"value": 1
}
],
"value": 0
}
},
"transform": [
],
"height": 372,
"width": 536
}
One way to do this is by replacing your "format" with an appropriate "labelExpr":
"axis": {
"labelAngle": -90,
"labelExpr": "isValid(datum.value) ? timeFormat(datum.value, '%I:%M') : 'null'",
"title": "Reservation On"
}

label bar chart in Vega Lite with both absolute number and percentage

I am able to label a bar chart created in Vega Lite, with either its percentage of the total or its absolute number, like so:
And here's the spec:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"width": "container",
"height": "container",
"data": {
"values": [
{
"binMin": -300,
"binMax": 0,
"binName": "-5 to 0 minutes",
"count": 29,
"percentOfTotal": 0.14215686274509803
},
{
"binMin": 0,
"binMax": 360,
"binName": "0 to +6 minutes",
"count": 51,
"percentOfTotal": 0.25
},
{
"binMin": 360,
"binMax": 600,
"binName": "+6 to +10 minutes",
"count": 32,
"percentOfTotal": 0.1568627450980392
},
{
"binMin": 600,
"binMax": 1200,
"binName": "+10 to +20 minutes",
"count": 90,
"percentOfTotal": 0.4411764705882353
}
]
},
"layer": [
{"mark": "bar"},
{
"mark": {
"type": "text",
"align": "center",
"yOffset": -10,
"fontSize": 18
},
"encoding": {
"text": {
"field": "percentOfTotal",
"type": "quantitative",
"format": ".0%",
"formatType": "number"
}
}
}
],
"encoding": {
"x": {
"field": "binName",
"type": "nominal",
"title": "Wait Time for Transfer (Minutes)",
"axis": {"titleFontSize": 18, "labelAngle": 0, "labelFontSize": 14},
"sort": {"field": "binMin"}
},
"y": {
"field": "count",
"type": "quantitative",
"title": "Total Transfers",
"axis": {"titleFontSize": 18, "labelFontSize": 14}
},
"color": {
"legend": false,
"field": "binMin",
"scale": {"range": ["red", "orange", "green", "yellowgreen"]}
}
}
}
I would like to change the label to display both, like a label for the left/red bar of "29 (14%)".
I have figured out how to set config.customFormatTypes = true and to write a little formatter function in JavaScript. However, I am unclear how I would be able to pass two fields into this formatter, in order to pass it both the absolute number and the percentage (or the absolute number for that category and the total number across all categories).
Any pointers? Thanks.
To display the concatenated value of 2 fields "29 (14%)" over text you can use transform calculate and generate a concatenated string based on your field. Then, use that field in your text mark as done below or refer editor:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"width": "container",
"height": "container",
"data": {
"values": [
{
"binMin": -300,
"binMax": 0,
"binName": "-5 to 0 minutes",
"count": 29,
"percentOfTotal": 0.14215686274509803
},
{
"binMin": 0,
"binMax": 360,
"binName": "0 to +6 minutes",
"count": 51,
"percentOfTotal": 0.25
},
{
"binMin": 360,
"binMax": 600,
"binName": "+6 to +10 minutes",
"count": 32,
"percentOfTotal": 0.1568627450980392
},
{
"binMin": 600,
"binMax": 1200,
"binName": "+10 to +20 minutes",
"count": 90,
"percentOfTotal": 0.4411764705882353
}
]
},
"layer": [
{"mark": "bar"},
{
"transform": [
{
"calculate": "format(datum.percentOfTotal, '.0%')",
"as": "perc_total"
},
{
"calculate": "datum.count+' (' +datum.perc_total +')'",
"as": "countPercentText"
}
],
"mark": {
"type": "text",
"align": "center",
"yOffset": -10,
"fontSize": 18
},
"encoding": {"text": {"field": "countPercentText", "type": "ordinal"}}
}
],
"encoding": {
"x": {
"field": "binName",
"type": "nominal",
"title": "Wait Time for Transfer (Minutes)",
"axis": {"titleFontSize": 18, "labelAngle": 0, "labelFontSize": 14},
"sort": {"field": "binMin"}
},
"y": {
"field": "count",
"type": "quantitative",
"title": "Total Transfers",
"axis": {"titleFontSize": 18, "labelFontSize": 14}
},
"color": {
"legend": false,
"field": "binMin",
"scale": {"range": ["red", "orange", "green", "yellowgreen"]}
}
}
}

Customise vega-lite Line Graph Axis Labels

What I want to do is really simple, but I just can't seem to get it right. I have a feeling I'm going to be embarrassed by the answer!
I have a line graph with "attempt" along the x-axis and "grade" along the y-axis, with grade being a number between 0 and 100. I simply want to change the y-axis so that, instead of seeing the raw number, a grade is show, say with 0 - 20 representing "E", 20-40 being "D" etc up to "A" (80-100). How can I do that? I don't want to use discrete values because I want to visually show where within a grade boundary a grade falls. I'm not sure whether I yet want to simply display the grade bands on the line or put them in the middle of their ticks, but just getting somewhere with this would help a lot!
Here is what I've been working with in the vega-lite editor:
{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"data": {
"values": [
{
"attempt": 1,
"score": 30
},
{
"attempt": 2,
"score": 60
},
{
"attempt": 3,
"score": 75
},
{
"attempt": 4,
"score": 58
},
{
"attempt": 5,
"score": 67
}
]
},
"mark": {
"type": "line",
"color": "#22bc9a",
"point": {
"filled": false
}
},
"encoding": {
"x": {
"field": "attempt",
"type": "quantitative",
"axis": {
"grid": false,
"tickCount": 5,
"title": "Attempt"
}
},
"y": {
"field": "score",
"scale": {"domain": [0, 100]},
"type": "quantitative",
"axis": {
"tickCount": 5,
"title": "Grade"
}
},
"opacity": {"value": 0.3}
},
"config": {
"autosize": "fit",
"axis": {
"labelColor": "#bebec8",
"tickColor": "#bebec8",
"titleColor": "black",
"titleFontWeight": "normal",
"titleFontSize": 11,
"labelFont": "Helvetica",
"titleFont": "Helvetica",
"gridOpacity": 0.4,
"gridWidth": 1.5,
"domain": false
},
"view": {
"strokeWidth": 0
}
}
}
Thanks in advance.
What about something like this: I add a dataframe with the grade category, and use this to layer some text. I remove the labels of the axis and so the text acts as if it were the labels of the axis.
The chart looks like this, and here is a link to the editor:
Schema (Note that I did it with Python's Altair, so it may not be canonical Vega-lite, and I did not use your settings either, sorry about that):
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.6.0.json",
"config": {
"view": {
"height": 300,
"width": 400
}
},
"datasets": {
"data-1acee7c5d817865a529b53e022474ce8": [
{
"label": "E",
"x_min": 1,
"y_med": 10
},
{
"label": "D",
"x_min": 1,
"y_med": 30
},
{
"label": "C",
"x_min": 1,
"y_med": 50
},
{
"label": "B",
"x_min": 1,
"y_med": 70
},
{
"label": "A",
"x_min": 1,
"y_med": 90
}
],
"data-8e6359ea3034b8410708361bb10fafd5": [
{
"attempt": 1,
"score": 30
},
{
"attempt": 2,
"score": 60
},
{
"attempt": 3,
"score": 75
},
{
"attempt": 4,
"score": 58
},
{
"attempt": 5,
"score": 67
}
]
},
"layer": [
{
"data": {
"name": "data-1acee7c5d817865a529b53e022474ce8"
},
"encoding": {
"text": {
"field": "label",
"type": "ordinal"
},
"x": {
"field": "x_min",
"scale": {
"zero": false
},
"type": "quantitative"
},
"y": {
"axis": {
"labels": false,
"tickCount": 5,
"ticks": false
},
"field": "y_med",
"type": "quantitative"
}
},
"mark": {
"dx": -15,
"dy": 8,
"size": 15,
"type": "text"
}
},
{
"data": {
"name": "data-8e6359ea3034b8410708361bb10fafd5"
},
"encoding": {
"x": {
"axis": {
"tickCount": 5
},
"field": "attempt",
"title": "Attempt",
"type": "quantitative"
},
"y": {
"field": "score",
"scale": {
"domain": [
0,
100
]
},
"title": "Grade",
"type": "quantitative"
}
},
"mark": {
"point": true,
"type": "line"
}
}
]
}
Using a slighly modified dataframe for the categories (with x_max, y_min and y_max added), you can add another layer with colored rectangles, that can help read the values:
Here is a link to the editor
And here is the schema
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.6.0.json",
"config": {
"view": {
"height": 300,
"width": 400
}
},
"datasets": {
"data-1acee7c5d817865a529b53e022474ce8": [
{
"label": "E",
"x_min": 1,
"y_med": 10
},
{
"label": "D",
"x_min": 1,
"y_med": 30
},
{
"label": "C",
"x_min": 1,
"y_med": 50
},
{
"label": "B",
"x_min": 1,
"y_med": 70
},
{
"label": "A",
"x_min": 1,
"y_med": 90
}
],
"data-39ffbda2b5d5fe96de84d9e308d920ff": [
{
"label": "E",
"x_max": 5,
"x_min": 1,
"y_max": 20,
"y_med": 10,
"y_min": 0
},
{
"label": "D",
"x_max": 5,
"x_min": 1,
"y_max": 40,
"y_med": 30,
"y_min": 20
},
{
"label": "C",
"x_max": 5,
"x_min": 1,
"y_max": 60,
"y_med": 50,
"y_min": 40
},
{
"label": "B",
"x_max": 5,
"x_min": 1,
"y_max": 80,
"y_med": 70,
"y_min": 60
},
{
"label": "A",
"x_max": 5,
"x_min": 1,
"y_max": 100,
"y_med": 90,
"y_min": 80
}
],
"data-8e6359ea3034b8410708361bb10fafd5": [
{
"attempt": 1,
"score": 30
},
{
"attempt": 2,
"score": 60
},
{
"attempt": 3,
"score": 75
},
{
"attempt": 4,
"score": 58
},
{
"attempt": 5,
"score": 67
}
]
},
"layer": [
{
"data": {
"name": "data-39ffbda2b5d5fe96de84d9e308d920ff"
},
"encoding": {
"color": {
"field": "label",
"scale": {
"scheme": "greenblue"
},
"type": "ordinal"
},
"x": {
"field": "x_min",
"scale": {
"zero": false
},
"title": "Attempt",
"type": "quantitative"
},
"x2": {
"field": "x_max",
"type": "quantitative"
},
"y": {
"axis": null,
"field": "y_min",
"type": "quantitative"
},
"y2": {
"field": "y_max",
"type": "quantitative"
}
},
"mark": "rect"
},
{
"data": {
"name": "data-1acee7c5d817865a529b53e022474ce8"
},
"encoding": {
"text": {
"field": "label",
"type": "ordinal"
},
"x": {
"field": "x_min",
"scale": {
"zero": false
},
"type": "quantitative"
},
"y": {
"axis": {
"labels": false,
"tickCount": 5,
"ticks": false
},
"field": "y_med",
"type": "quantitative"
}
},
"mark": {
"dx": -15,
"dy": 8,
"size": 15,
"type": "text"
}
},
{
"data": {
"name": "data-8e6359ea3034b8410708361bb10fafd5"
},
"encoding": {
"x": {
"axis": {
"tickCount": 5
},
"field": "attempt",
"title": "Attempt",
"type": "quantitative"
},
"y": {
"field": "score",
"scale": {
"domain": [
0,
100
]
},
"title": "Grade",
"type": "quantitative"
}
},
"mark": {
"point": true,
"type": "line"
}
}
]
}
To get it working, I first had to change the encoding of the x and y axis to be ordinal. Then I mapped your input data values to letter grades before creating the schema:
//replace every score value with correct letter grade
values.forEach(datapoint => {
if(datapoint.score > 90) {
datapoint.score = "A";
} else if(datapoint.score > 80) {
datapoint.score = "B";
} else if (datapoint.score > 70) {
//so on...
}
});
Here is a working example in the vega-lite editor:
Line Chart with Ordinal Values
Here is the schema:
{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"data": {
"values": [
{
"attempt": 1,
"score": "F"
},
{
"attempt": 2,
"score": "D"
},
{
"attempt": 3,
"score": "C"
},
{
"attempt": 4,
"score": "F"
},
{
"attempt": 5,
"score": "D"
}
]
},
"mark": {
"type": "line",
"color": "#22bc9a",
"point": {
"filled": false
}
},
"encoding": {
"x": {
"field": "attempt",
"type": "ordinal",
"axis": {
"title": "Attempt"
}
},
"y": {
"field": "score",
"type": "ordinal",
"axis": {
"title": "Grade"
}
},
"opacity": {"value": 0.3}
},
"config": {
"autosize": "fit",
"axis": {
"labelColor": "#bebec8",
"tickColor": "#bebec8",
"titleColor": "black",
"titleFontWeight": "normal",
"titleFontSize": 11,
"labelFont": "Helvetica",
"titleFont": "Helvetica",
"gridOpacity": 0.4,
"gridWidth": 1.5
},
"view": {
"strokeWidth": 0
}
}
}

parsing a large multi nested json into scala case class

Below is a json example of Twitter's tweet. It's a large json. What is the best library/method to parse it into a case class in scala?
For instance, in Play Framework 2.x it's possible to do that with it's internal library by defining case classes and implicit conversions, but in this case I don't use Play. Should I?
spray-json seems to be most popular scala json library, but in this case it looks quite disappointing - standard approach seems to be limited to 22 elements and uses pattern matching, which becomes ridiculous in the context of multi nested structure with hundreds of elements. Any ideas?
{
"created_at": "Sat Oct 24 06:44:34 +0000 2015",
"id": 657809891558576132,
"id_str": "657809891558576132",
"text": "RT #M23projects: Kara Walker \"Go to Hell or Atlanta, Whichever Come First\" #victoriamiro #London https://t.co/HapqKa4i0l https://t.co/95G…",
"source": "Twitter for iPhone",
"truncated": false,
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 2792146884,
"id_str": "2792146884",
"name": "Tonbridge School Art",
"screen_name": "ArtTonSchool",
"location": "Tonbridge",
"url": null,
"description": "Tonbridge School is an independent day and boarding school for boys. Tweets by the Art Department.",
"protected": false,
"verified": false,
"followers_count": 187,
"friends_count": 288,
"listed_count": 10,
"favourites_count": 1069,
"statuses_count": 1764,
"created_at": "Fri Sep 05 15:37:43 +0000 2014",
"utc_offset": 3600,
"time_zone": "London",
"geo_enabled": true,
"lang": "en-gb",
"contributors_enabled": false,
"is_translator": false,
"profile_background_color": "C0DEED",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_link_color": "0084B4",
"profile_sidebar_border_color": "C0DEED",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"profile_image_url": "http://pbs.twimg.com/profile_images/507921409738543104/V35eZACR_normal.jpeg",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/507921409738543104/V35eZACR_normal.jpeg",
"profile_banner_url": "https://pbs.twimg.com/profile_banners/2792146884/1410119421",
"default_profile": true,
"default_profile_image": false,
"following": null,
"follow_request_sent": null,
"notifications": null
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"retweeted_status": {
"created_at": "Sat Oct 24 02:27:06 +0000 2015",
"id": 657745100739506176,
"id_str": "657745100739506176",
"text": "Kara Walker \"Go to Hell or Atlanta, Whichever Come First\" #victoriamiro #London https://t.co/HapqKa4i0l https://t.co/95GaLC4XTo",
"source": "Twitter for iPhone",
"truncated": false,
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 999716342,
"id_str": "999716342",
"name": "M23",
"screen_name": "M23projects",
"location": "New York",
"url": "http://M23.co",
"description": "M23's project space + itinerant program promotes new work by new artists. \nhttp://Instagram.com/m23projects",
"protected": false,
"verified": false,
"followers_count": 9150,
"friends_count": 7353,
"listed_count": 174,
"favourites_count": 1354,
"statuses_count": 4666,
"created_at": "Sun Dec 09 17:13:35 +0000 2012",
"utc_offset": -14400,
"time_zone": "Eastern Time (US & Canada)",
"geo_enabled": true,
"lang": "en",
"contributors_enabled": false,
"is_translator": false,
"profile_background_color": "547587",
"profile_background_image_url": "http://pbs.twimg.com/profile_background_images/884257252/e329bbc1b91d695862d5b23a209f2d34.jpeg",
"profile_background_image_url_https": "https://pbs.twimg.com/profile_background_images/884257252/e329bbc1b91d695862d5b23a209f2d34.jpeg",
"profile_background_tile": true,
"profile_link_color": "414A4D",
"profile_sidebar_border_color": "FFFFFF",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"profile_image_url": "http://pbs.twimg.com/profile_images/458985956830236673/Z_4Bq9PJ_normal.jpeg",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/458985956830236673/Z_4Bq9PJ_normal.jpeg",
"profile_banner_url": "https://pbs.twimg.com/profile_banners/999716342/1398650659",
"default_profile": false,
"default_profile_image": false,
"following": null,
"follow_request_sent": null,
"notifications": null
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": false,
"retweet_count": 2,
"favorite_count": 3,
"entities": {
"hashtags": [
{
"text": "London",
"indices": [
74,
81
]
}
],
"urls": [
{
"url": "https://t.co/HapqKa4i0l",
"expanded_url": "http://instagram.com/m23projects",
"display_url": "instagram.com/m23projects",
"indices": [
82,
105
]
}
],
"user_mentions": [
{
"screen_name": "victoriamiro",
"name": "Victoria Miro",
"id": 373924746,
"id_str": "373924746",
"indices": [
58,
71
]
}
],
"symbols": [],
"media": [
{
"id": 657745078413201408,
"id_str": "657745078413201408",
"indices": [
106,
129
],
"media_url": "http://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 255,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 450,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 768,
"resize": "fit"
}
}
}
]
},
"extended_entities": {
"media": [
{
"id": 657745078413201408,
"id_str": "657745078413201408",
"indices": [
106,
129
],
"media_url": "http://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 255,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 450,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 768,
"resize": "fit"
}
}
},
{
"id": 657745085275095040,
"id_str": "657745085275095040",
"indices": [
106,
129
],
"media_url": "http://pbs.twimg.com/media/CSDHq5CUwAAC-6a.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHq5CUwAAC-6a.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 453,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 800,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 768,
"h": 1024,
"resize": "fit"
}
}
},
{
"id": 657745085300277248,
"id_str": "657745085300277248",
"indices": [
106,
129
],
"media_url": "http://pbs.twimg.com/media/CSDHq5IVAAAn2YH.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHq5IVAAAn2YH.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 453,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 800,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 768,
"h": 1024,
"resize": "fit"
}
}
},
{
"id": 657745085275082752,
"id_str": "657745085275082752",
"indices": [
106,
129
],
"media_url": "http://pbs.twimg.com/media/CSDHq5CUkAAd0oL.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHq5CUkAAd0oL.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 255,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 450,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 768,
"resize": "fit"
}
}
}
]
},
"favorited": false,
"retweeted": false,
"possibly_sensitive": false,
"filter_level": "low",
"lang": "en"
},
"is_quote_status": false,
"retweet_count": 0,
"favorite_count": 0,
"entities": {
"hashtags": [
{
"text": "London",
"indices": [
91,
98
]
}
],
"urls": [
{
"url": "https://t.co/HapqKa4i0l",
"expanded_url": "http://instagram.com/m23projects",
"display_url": "instagram.com/m23projects",
"indices": [
99,
122
]
}
],
"user_mentions": [
{
"screen_name": "M23projects",
"name": "M23",
"id": 999716342,
"id_str": "999716342",
"indices": [
3,
15
]
},
{
"screen_name": "victoriamiro",
"name": "Victoria Miro",
"id": 373924746,
"id_str": "373924746",
"indices": [
75,
88
]
}
],
"symbols": [],
"media": [
{
"id": 657745078413201408,
"id_str": "657745078413201408",
"indices": [
123,
140
],
"media_url": "http://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 255,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 450,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 768,
"resize": "fit"
}
},
"source_status_id": 657745100739506176,
"source_status_id_str": "657745100739506176",
"source_user_id": 999716342,
"source_user_id_str": "999716342"
}
]
},
"extended_entities": {
"media": [
{
"id": 657745078413201408,
"id_str": "657745078413201408",
"indices": [
123,
140
],
"media_url": "http://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHqfeUkAA4a0Y.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 255,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 450,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 768,
"resize": "fit"
}
},
"source_status_id": 657745100739506176,
"source_status_id_str": "657745100739506176",
"source_user_id": 999716342,
"source_user_id_str": "999716342"
},
{
"id": 657745085275095040,
"id_str": "657745085275095040",
"indices": [
123,
140
],
"media_url": "http://pbs.twimg.com/media/CSDHq5CUwAAC-6a.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHq5CUwAAC-6a.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 453,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 800,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 768,
"h": 1024,
"resize": "fit"
}
},
"source_status_id": 657745100739506176,
"source_status_id_str": "657745100739506176",
"source_user_id": 999716342,
"source_user_id_str": "999716342"
},
{
"id": 657745085300277248,
"id_str": "657745085300277248",
"indices": [
123,
140
],
"media_url": "http://pbs.twimg.com/media/CSDHq5IVAAAn2YH.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHq5IVAAAn2YH.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 453,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 800,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 768,
"h": 1024,
"resize": "fit"
}
},
"source_status_id": 657745100739506176,
"source_status_id_str": "657745100739506176",
"source_user_id": 999716342,
"source_user_id_str": "999716342"
},
{
"id": 657745085275082752,
"id_str": "657745085275082752",
"indices": [
123,
140
],
"media_url": "http://pbs.twimg.com/media/CSDHq5CUkAAd0oL.jpg",
"media_url_https": "https://pbs.twimg.com/media/CSDHq5CUkAAd0oL.jpg",
"url": "https://t.co/95GaLC4XTo",
"display_url": "pic.twitter.com/95GaLC4XTo",
"expanded_url": "http://twitter.com/M23projects/status/657745100739506176/photo/1",
"type": "photo",
"sizes": {
"small": {
"w": 340,
"h": 255,
"resize": "fit"
},
"medium": {
"w": 600,
"h": 450,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"large": {
"w": 1024,
"h": 768,
"resize": "fit"
}
},
"source_status_id": 657745100739506176,
"source_status_id_str": "657745100739506176",
"source_user_id": 999716342,
"source_user_id_str": "999716342"
}
]
},
"favorited": false,
"retweeted": false,
"possibly_sensitive": false,
"filter_level": "low",
"lang": "en",
"timestamp_ms": "1445669074321"
}
**UPDATE: ** I guess I should stick to play-json, even more so for performance reasons - http://derekwyatt.org/2014/01/15/benchmarking-spray-json-argonaut-play-json/
You can depends on Play's JSON library by itself:
// build.sbt
libraryDependencies += "com.typesafe.play" % "play-json_2.11" % "X.X.X"
// Tweet.scala
import play.api.libs.json._
case class User(id: String, name: String, ...)
implicit val userFormat = Json.format[User]
case class Tweet(id: String, content: String, user: User)
implicit val tweetFormat = Json.format[Tweet]
This will use play-json's macros to auto-generate the formatters you need to parse JSON into instances of Tweet and User.
Regardless of library you choose you won't find an elegant solution for handling more than 22 fields since that's a limitation of the case class implementation (up until 2.11) rather than any specific design choice by a library.

source code of the HTML5 version of Angry birds visible?

Today I read that Rovio released Angry birds for Chrome i.e HTML5 compatible. Does it mean that anyone can see the source code of the HTML5 version of the game now?
Yes, but it's not very readable as it looks to be generated from a Java input, probably via GWT.
The levels are stored as JSON – here's the level 2 file:
{
"camera": [
{
"bottom": -51.69,
"id": "Slingshot",
"left": -28.397,
"right": 47.013,
"top": -51.69,
"x": 28.621,
"y": -13.985
},
{
"bottom": -49.048,
"id": "Castle",
"left": 12.344,
"right": 82.582,
"top": -49.048,
"x": 66.776,
"y": -13.929
}
],
"counts": {
"birds": 5,
"blocks": 27
},
"id": "pack1/Level57.lua",
"scoreEagle": 29000,
"scoreGold": 60000,
"scoreSilver": 47000,
"theme": "BACKGROUND_BLUE_GRASS",
"world": {
"bird_1": {
"angle": 0,
"id": "BIRD_RED",
"x": 9.93,
"y": -4.328
},
"bird_2": {
"angle": 0,
"id": "BIRD_RED",
"x": 7.489,
"y": -4.339
},
"bird_3": {
"angle": 0,
"id": "BIRD_RED",
"x": 5.417,
"y": -4.249
},
"bird_4": {
"angle": 0,
"id": "BIRD_RED",
"x": 3.42,
"y": -4.339
},
"bird_5": {
"angle": 0,
"id": "BIRD_RED",
"x": 0,
"y": -1.035
},
"block_1": {
"angle": 90.027,
"id": "STONE_BLOCK_4X1",
"x": 61.498,
"y": -7.314
},
"block_10": {
"angle": 180,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 74.143,
"y": -0.157
},
"block_11": {
"angle": 180,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 83.499,
"y": -0.107
},
"block_12": {
"angle": 180,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 92.925,
"y": -0.058
},
"block_13": {
"angle": 0,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 7.156,
"y": 1.484
},
"block_14": {
"angle": 135,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 111.252,
"y": -18.195
},
"block_15": {
"angle": 24.537,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 3.616,
"y": -0.22
},
"block_16": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 11.912,
"y": -0.041
},
"block_17": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 103.199,
"y": -0.037
},
"block_18": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 106.374,
"y": -3.514
},
"block_19": {
"angle": 45,
"id": "TERRAIN_TEXTURED_HILLS_5X5",
"x": 109.7,
"y": -0.188
},
"block_2": {
"angle": 89.999,
"id": "STONE_BLOCK_4X1",
"x": 68.165,
"y": -7.317
},
"block_20": {
"angle": 359.713,
"id": "PIG_BASIC_SMALL",
"x": 85.85,
"y": -15.34
},
"block_21": {
"angle": 2.262,
"id": "PIG_BASIC_SMALL",
"x": 75.084,
"y": -11.419
},
"block_22": {
"angle": 7.16,
"id": "PIG_BASIC_SMALL",
"x": 68.143,
"y": -11.427
},
"block_23": {
"angle": 0.153,
"id": "PIG_BASIC_SMALL",
"x": 61.475,
"y": -11.411
},
"block_24": {
"angle": 179.984,
"id": "WOOD_BLOCK_4X1",
"x": 85.911,
"y": -13.755
},
"block_25": {
"angle": 180.065,
"id": "WOOD_BLOCK_4X1",
"x": 75.051,
"y": -9.834
},
"block_26": {
"angle": 180.172,
"id": "WOOD_BLOCK_4X1",
"x": 68.284,
"y": -9.842
},
"block_27": {
"angle": 0.112,
"id": "WOOD_BLOCK_4X1",
"x": 61.463,
"y": -9.83
},
"block_3": {
"angle": 90.017,
"id": "STONE_BLOCK_4X1",
"x": 74.983,
"y": -7.316
},
"block_4": {
"angle": 270,
"id": "STONE_BLOCK_8X1",
"x": 85.892,
"y": -9.272
},
"block_5": {
"angle": 359.999,
"id": "TERRAIN_TEXTURED_HILLS_32X2",
"x": 75.877,
"y": -4.433
},
"block_6": {
"angle": 225.001,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 98.165,
"y": -5.15
},
"block_7": {
"angle": 225.001,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 104.615,
"y": -11.599
},
"block_8": {
"angle": 90,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 64.836,
"y": -0.135
},
"block_9": {
"angle": 135,
"id": "TERRAIN_TEXTURED_HILLS_10X10",
"x": 60.034,
"y": 1.675
}
}
}
This means that you could potentially inject your own levels by intercepting the requests.
Yes, but it is heavily obfuscated, see small part of code below:
function d3(){this.b=new Date}
function MK(){this.o=EU.d.Nc()}
function TE(b,c){b.i.k=c;b.f=4}
function PU(b,c,d){b.f=c;b.g=d}
function YF(b){b.f=6;b.b=false}
function YH(b){b.f=6;b.b=false}
function iG(b){b.f=7;b.b=false}
They use the google PlayN framework for the HTML5 port.
See https://developers.google.com/playn/
It means you can see the HTML5 code, but it will not be very useful since it's compiled with GWT and not very understandable.