Forum Discussion
Deneb: Packing instead of Overlapping Bubbles in Scatter Plot
Something like this?
Deneb-Showcase/S&P Beeswarm Chart at main · PBI-David/Deneb-Showcase · GitHub
or this?
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"usermeta": {
"deneb": {
"build": "1.4.0.0",
"metaVersion": 1,
"provider": "vega",
"providerVersion": "5.22.1"
},
"interactivity": {
"tooltip": true,
"contextMenu": true,
"selection": false,
"highlight": true,
"dataPointLimit": 50
},
"information": {
"name": "Kerry Kolosko Bubble Swarm",
"description": "[No Description Provided]",
"author": "Kerry Kolosko",
"uuid": "e363f508-0281-4f62-a1a3-115169706015",
"generated": "2023-03-03T08:30:42.639Z"
},
"dataset": [
{
"key": "__0__",
"name": "X",
"description": "",
"type": "numeric",
"kind": "column"
},
{
"key": "__1__",
"name": "ColourCategory",
"description": "",
"type": "text",
"kind": "column"
},
{
"key": "__2__",
"name": "Labels",
"description": "",
"type": "text",
"kind": "column"
},
{
"key": "__3__",
"name": "Y",
"description": "",
"type": "numeric",
"kind": "measure"
},
{
"key": "__4__",
"name": "BubbleSize",
"description": "",
"type": "numeric",
"kind": "measure"
}
]
},
"config": {
"autosize": {
"contains": "padding",
"type": "fit"
},
"view": {"stroke": "transparent"},
"font": "Segoe UI",
"arc": {},
"area": {
"line": true,
"opacity": 0.6
},
"bar": {},
"line": {
"strokeWidth": 3,
"strokeCap": "round",
"strokeJoin": "round"
},
"path": {},
"point": {
"filled": true,
"size": 75
},
"rect": {},
"shape": {},
"symbol": {
"strokeWidth": 1.5,
"size": 50
},
"text": {
"font": "Segoe UI",
"fontSize": 12,
"fill": "#605E5C"
},
"axis": {
"ticks": false,
"grid": false,
"domain": false,
"labelColor": "transparent",
"labelFontSize": 12,
"titleFont": "wf_standard-font, helvetica, arial, sans-serif",
"titleColor": "#252423",
"titleFontSize": 16,
"titleFontWeight": "normal"
},
"axisQuantitative": {
"tickCount": 3,
"grid": true,
"gridColor": "#C8C6C4",
"gridDash": [1, 5],
"labelFlush": false
},
"axisX": {"labelPadding": 5},
"axisY": {"labelPadding": 10},
"header": {
"titleFont": "wf_standard-font, helvetica, arial, sans-serif",
"titleFontSize": 16,
"titleColor": "#252423",
"labelFont": "Segoe UI",
"labelFontSize": 13.333333333333332,
"labelColor": "#605E5C"
},
"legend": {
"titleFont": "Segoe UI",
"titleFontWeight": "bold",
"titleColor": "#605E5C",
"labelFont": "Segoe UI",
"labelFontSize": 13.333333333333332,
"labelColor": "#605E5C",
"symbolType": "circle",
"symbolSize": 75
}
},
"data": [{"name": "dataset"}],
"signals": [
{
"name": "cx",
"update": "width / 2"
},
{
"name": "cy",
"update": "height / 2"
},
{"name": "radius", "value": 8},
{"name": "collide", "value": 0.1},
{"name": "gravityX", "value": 0.2},
{"name": "gravityY", "value": 0.2},
{"name": "static", "value": true}
],
"scales": [
{
"name": "xscale",
"type": "linear",
"domainMin": -100,
"domainMax": 140,
"domain": {
"data": "dataset",
"field": "__3__",
"sort": true
},
"range": "width"
},
{
"name": "yscale",
"type": "linear",
"range": "height",
"nice": true,
"domain": {
"data": "dataset",
"field": "__0__",
"sort": false
}
},
{
"name": "color",
"type": "ordinal",
"domain": {
"data": "dataset",
"field": "__1__"
},
"range": {"scheme": "category20c"}
},
{
"name": "ballsize",
"domain": {
"data": "dataset",
"field": "__4__"
},
"range": [0, 50000]
}
],
"axes": [
{
"orient": "bottom",
"scale": "xscale"
},
{
"orient": "left",
"scale": "yscale",
"tickCount": 5,
"zindex": 1
}
],
"marks": [
{
"name": "nodes",
"type": "symbol",
"from": {"data": "dataset"},
"encode": {
"enter": {
"fill": {
"scale": "color",
"field": "__1__"
},
"xfocus": {
"scale": "xscale",
"field": "__3__",
"band": 0.5
},
"yfocus": {
"scale": "yscale",
"field": "__0__",
"band": 0.5
}
},
"update": {
"size": {
"scale": "ballsize",
"field": "__4__"
},
"stroke": {"value": "white"},
"strokeWidth": {"value": 1},
"zindex": {"value": 0},
"tooltip": {"signal": "datum"}
},
"hover": {
"stroke": {"value": "purple"},
"strokeWidth": {"value": 3},
"zindex": {"value": 1}
}
},
"transform": [
{
"type": "force",
"iterations": 100,
"forces": [
{
"force": "collide",
"iterations": {
"signal": "collide"
},
"radius": {
"expr": "sqrt(datum.size)/ 2"
}
},
{
"force": "x",
"x": "xfocus",
"strength": {
"signal": "gravityX"
}
},
{
"force": "y",
"y": "yfocus",
"strength": {
"signal": "gravityY"
}
}
]
}
]
},
{
"type": "text",
"from": {"data": "nodes"},
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {
"value": "middle"
},
"fontSize": {
"scale": "ballsize",
"field": "__4__"
},
"fontWeight": {
"value": "bold"
},
"fill": {"value": "black"},
"text": {
"field": "datum['__2__']"
}
},
"update": {
"x": {"field": "x"},
"y": {"field": "y"}
},
"transform": [
{
"type": "label",
"avoidMarks": ["nodes"],
"anchor": [
"top",
"bottom",
"right",
"left"
],
"offset": [1],
"size": {
"signal": "[width + 60, height]"
}
}
]
}
}
]
}
Hi, this is beautiful work and much more than I requested.It will take a lot of time that I understand it and simplify for my use case.
Can you could help me to simplified it? I would be very thankful.
BR, Srđan
- giammariam3 years agoSolution Sage
I was so in the weeds looking into circle packing that I completely forgot about the force transform 🤦🏻♂️. That should definitely work in the matrix format that you have.
Since they brought it up, I'll defer to KerKol, or avatorl so one of them can get credit for the solution. I may just see if I can get it implemented on my own just for practice.