Forum Discussion

Anonymous's avatar
Anonymous
Not applicable
3 years ago
Solved

Custom visual based on seat allocation

Is there a power bi custom visual based on seat allocation? for example: 

or is there anything similar custom visual to the screenshot above? 

All the colours are allocated seat in a company annual meeting.

 

 

  • I got this to work in the attached file by just modifying the Vega spec you posted slightly. Note that I needed to add a "person" field in my example to effectively generate a row per seat

     

     

    {
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "width": 550,
      "height": 300,
      "signals": [
        {
          "name": "dataLength",
          "update": "length(data('dataset'))"
        },
        {
          "name": "row0Radius",
          "value": 280
        },
        {
          "name": "row1Radius",
          "value": 260
        },
        {
          "name": "row2Radius",
          "value": 240
        },
        {
          "name": "row3Radius",
          "value": 220
        },
        {
          "name": "row4Radius",
          "value": 200
        },
        {
          "name": "row5Radius",
          "value": 180
        },
        {
          "name": "row6Radius",
          "value": 160
        },
        {
          "name": "row0Circ",
          "update": "PI*row0Radius"
        },
        {
          "name": "row1Circ",
          "update": "PI*row1Radius"
        },
        {
          "name": "row2Circ",
          "update": "PI*row2Radius"
        },
        {
          "name": "row3Circ",
          "update": "PI*row3Radius"
        },
        {
          "name": "row4Circ",
          "update": "PI*row4Radius"
        },
        {
          "name": "row5Circ",
          "update": "PI*row5Radius"
        },
        {
          "name": "row6Circ",
          "update": "PI*row6Radius"
        },
        {
          "name": "totalLength",
          "update": "row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ+row6Circ "
        }
      ],
      "data": [
        {
          "name": "dataset",
          "transform": [
            {
              "type": "project",
              "fields": ["Person", "Party"]
            },
            {
              "type": "window",
              "ops": ["row_number"],
              "fields": [null],
              "as": ["index"],
              "sort": {
                "field": "Party",
                "order": "descending"
              }
            }
          ]
        },
        {
          "name": "placement",
          "transform": [
            {
              "type": "sequence",
              "start": 1,
              "stop": {
                "signal": "dataLength+1"
              },
              "as": "index"
            },
            {
              "type": "formula",
              "as": "wholeCirc",
              "expr": "totalLength/dataLength"
            },
            {
              "type": "window",
              "ops": ["sum"],
              "fields": ["wholeCirc"],
              "as": ["cumWholeCirc"]
            },
            {
              "type": "formula",
              "as": "row",
              "expr": "datum.cumWholeCirc <row0Circ?0:datum.cumWholeCirc <row0Circ+row1Circ?1:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ?2:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ?3:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ?4:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ?5:6 "
            },
            {
              "type": "joinaggregate",
              "fields": ["Person"],
              "ops": ["count"],
              "groupby": ["row"],
              "as": ["rowCount"]
            },
            {
              "type": "formula",
              "as": "rowCirc",
              "expr": "datum.row==0?(row0Circ/(datum.rowCount-1)):datum.row==1?(row1Circ/(datum.rowCount-1)):datum.row==2?(row2Circ/(datum.rowCount-1)):datum.row==3?(row3Circ/(datum.rowCount-1)):datum.row==4?(row4Circ/(datum.rowCount-1)):datum.row==5?(row5Circ/(datum.rowCount-1)):datum.row==6?(row6Circ/(datum.rowCount-1)):0"
            },
            {
              "type": "window",
              "ops": ["sum"],
              "fields": ["rowCirc"],
              "groupby": ["row"],
              "sort": {
                "field": "index",
                "order": "descending"
              },
              "as": ["cumRowCirc"]
            },
            {
              "type": "formula",
              "as": "cumRowCircAct",
              "expr": "datum.cumRowCirc - datum.rowCirc "
            },
            {
              "type": "formula",
              "as": "theta",
              "expr": "datum.cumRowCircAct==0?0:datum.row==0?(datum.cumRowCircAct/row0Radius):datum.row==1?(datum.cumRowCircAct/row1Radius):datum.row==2?datum.cumRowCircAct/row2Radius:datum.row==3?datum.cumRowCircAct/row3Radius:datum.row==4?datum.cumRowCircAct/row4Radius:datum.row==5?datum.cumRowCircAct/row5Radius:datum.row==6?datum.cumRowCircAct/row6Radius:0"
            },
            {
              "type": "formula",
              "as": "x",
              "expr": "datum.row==0?row0Radius*cos(datum.theta):datum.row==1?row1Radius*cos(datum.theta):datum.row==2?row2Radius*cos(datum.theta):datum.row==3?row3Radius*cos(datum.theta):datum.row==4?row4Radius*cos(datum.theta):datum.row==5?row5Radius*cos(datum.theta):datum.row==6?row6Radius*cos(datum.theta):0"
            },
            {
              "type": "formula",
              "as": "y",
              "expr": "datum.row==0?row0Radius*sin(datum.theta):datum.row==1?row1Radius*sin(datum.theta):datum.row==2?row2Radius*sin(datum.theta):datum.row==3?row3Radius*sin(datum.theta):datum.row==4?row4Radius*sin(datum.theta):datum.row==5?row5Radius*sin(datum.theta):datum.row==6?row6Radius*sin(datum.theta):0"
            },
            {
              "type": "window",
              "sort": {
                "field": "theta",
                "order": "ascending"
              },
              "ops": ["row_number"],
              "fields": ["row_number"],
              "as": ["lookup"]
            },
            {
              "type": "lookup",
              "from": "dataset",
              "key": "index",
              "fields": ["lookup"],
              "values": ["Party"],
              "as": ["finalParty"]
            }
          ]
        }
      ],
      "scales": [
        {
          "name": "x",
          "type": "linear",
          "round": true,
          "nice": true,
          "zero": true,
          "domain": {
            "field": "x",
            "data": "placement"
          },
          "range": "width"
        },
        {
          "name": "y",
          "type": "linear",
          "round": true,
          "nice": true,
          "zero": true,
          "domain": {
            "field": "y",
            "data": "placement"
          },
          "range": "height"
        },
        {
          "name": "color",
          "type": "ordinal",
          "domain": {
            "data": "placement",
            "field": "finalParty"
          },
          "range": {"scheme": "pbiColorNominal"}
        }
      ],
      "marks": [
        {
          "name": "marks",
          "type": "symbol",
          "from": {"data": "placement"},
          "encode": {
            "update": {
              "x": {
                "scale": "x",
                "field": "x"
              },
              "y": {
                "scale": "y",
                "field": "y"
              },
              "shape": {"value": "circle"},
              "size": {"value": 130},
              "stroke": {
                "value": "#4682b4"
              },
              "tooltip": {
                "signal": "datum"
              },
              "fill": {
                "scale": "color",
                "field": "finalParty"
              }
            }
          }
        }
      ]
    }

     

    This is the updated Vega specification (note you need to change the setting in the Deneb visual to use the "Vega" provider instead of the default "Vega-Lite" provider)

     

5 Replies

  • I got this to work in the attached file by just modifying the Vega spec you posted slightly. Note that I needed to add a "person" field in my example to effectively generate a row per seat

     

     

    {
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "width": 550,
      "height": 300,
      "signals": [
        {
          "name": "dataLength",
          "update": "length(data('dataset'))"
        },
        {
          "name": "row0Radius",
          "value": 280
        },
        {
          "name": "row1Radius",
          "value": 260
        },
        {
          "name": "row2Radius",
          "value": 240
        },
        {
          "name": "row3Radius",
          "value": 220
        },
        {
          "name": "row4Radius",
          "value": 200
        },
        {
          "name": "row5Radius",
          "value": 180
        },
        {
          "name": "row6Radius",
          "value": 160
        },
        {
          "name": "row0Circ",
          "update": "PI*row0Radius"
        },
        {
          "name": "row1Circ",
          "update": "PI*row1Radius"
        },
        {
          "name": "row2Circ",
          "update": "PI*row2Radius"
        },
        {
          "name": "row3Circ",
          "update": "PI*row3Radius"
        },
        {
          "name": "row4Circ",
          "update": "PI*row4Radius"
        },
        {
          "name": "row5Circ",
          "update": "PI*row5Radius"
        },
        {
          "name": "row6Circ",
          "update": "PI*row6Radius"
        },
        {
          "name": "totalLength",
          "update": "row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ+row6Circ "
        }
      ],
      "data": [
        {
          "name": "dataset",
          "transform": [
            {
              "type": "project",
              "fields": ["Person", "Party"]
            },
            {
              "type": "window",
              "ops": ["row_number"],
              "fields": [null],
              "as": ["index"],
              "sort": {
                "field": "Party",
                "order": "descending"
              }
            }
          ]
        },
        {
          "name": "placement",
          "transform": [
            {
              "type": "sequence",
              "start": 1,
              "stop": {
                "signal": "dataLength+1"
              },
              "as": "index"
            },
            {
              "type": "formula",
              "as": "wholeCirc",
              "expr": "totalLength/dataLength"
            },
            {
              "type": "window",
              "ops": ["sum"],
              "fields": ["wholeCirc"],
              "as": ["cumWholeCirc"]
            },
            {
              "type": "formula",
              "as": "row",
              "expr": "datum.cumWholeCirc <row0Circ?0:datum.cumWholeCirc <row0Circ+row1Circ?1:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ?2:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ?3:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ?4:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ?5:6 "
            },
            {
              "type": "joinaggregate",
              "fields": ["Person"],
              "ops": ["count"],
              "groupby": ["row"],
              "as": ["rowCount"]
            },
            {
              "type": "formula",
              "as": "rowCirc",
              "expr": "datum.row==0?(row0Circ/(datum.rowCount-1)):datum.row==1?(row1Circ/(datum.rowCount-1)):datum.row==2?(row2Circ/(datum.rowCount-1)):datum.row==3?(row3Circ/(datum.rowCount-1)):datum.row==4?(row4Circ/(datum.rowCount-1)):datum.row==5?(row5Circ/(datum.rowCount-1)):datum.row==6?(row6Circ/(datum.rowCount-1)):0"
            },
            {
              "type": "window",
              "ops": ["sum"],
              "fields": ["rowCirc"],
              "groupby": ["row"],
              "sort": {
                "field": "index",
                "order": "descending"
              },
              "as": ["cumRowCirc"]
            },
            {
              "type": "formula",
              "as": "cumRowCircAct",
              "expr": "datum.cumRowCirc - datum.rowCirc "
            },
            {
              "type": "formula",
              "as": "theta",
              "expr": "datum.cumRowCircAct==0?0:datum.row==0?(datum.cumRowCircAct/row0Radius):datum.row==1?(datum.cumRowCircAct/row1Radius):datum.row==2?datum.cumRowCircAct/row2Radius:datum.row==3?datum.cumRowCircAct/row3Radius:datum.row==4?datum.cumRowCircAct/row4Radius:datum.row==5?datum.cumRowCircAct/row5Radius:datum.row==6?datum.cumRowCircAct/row6Radius:0"
            },
            {
              "type": "formula",
              "as": "x",
              "expr": "datum.row==0?row0Radius*cos(datum.theta):datum.row==1?row1Radius*cos(datum.theta):datum.row==2?row2Radius*cos(datum.theta):datum.row==3?row3Radius*cos(datum.theta):datum.row==4?row4Radius*cos(datum.theta):datum.row==5?row5Radius*cos(datum.theta):datum.row==6?row6Radius*cos(datum.theta):0"
            },
            {
              "type": "formula",
              "as": "y",
              "expr": "datum.row==0?row0Radius*sin(datum.theta):datum.row==1?row1Radius*sin(datum.theta):datum.row==2?row2Radius*sin(datum.theta):datum.row==3?row3Radius*sin(datum.theta):datum.row==4?row4Radius*sin(datum.theta):datum.row==5?row5Radius*sin(datum.theta):datum.row==6?row6Radius*sin(datum.theta):0"
            },
            {
              "type": "window",
              "sort": {
                "field": "theta",
                "order": "ascending"
              },
              "ops": ["row_number"],
              "fields": ["row_number"],
              "as": ["lookup"]
            },
            {
              "type": "lookup",
              "from": "dataset",
              "key": "index",
              "fields": ["lookup"],
              "values": ["Party"],
              "as": ["finalParty"]
            }
          ]
        }
      ],
      "scales": [
        {
          "name": "x",
          "type": "linear",
          "round": true,
          "nice": true,
          "zero": true,
          "domain": {
            "field": "x",
            "data": "placement"
          },
          "range": "width"
        },
        {
          "name": "y",
          "type": "linear",
          "round": true,
          "nice": true,
          "zero": true,
          "domain": {
            "field": "y",
            "data": "placement"
          },
          "range": "height"
        },
        {
          "name": "color",
          "type": "ordinal",
          "domain": {
            "data": "placement",
            "field": "finalParty"
          },
          "range": {"scheme": "pbiColorNominal"}
        }
      ],
      "marks": [
        {
          "name": "marks",
          "type": "symbol",
          "from": {"data": "placement"},
          "encode": {
            "update": {
              "x": {
                "scale": "x",
                "field": "x"
              },
              "y": {
                "scale": "y",
                "field": "y"
              },
              "shape": {"value": "circle"},
              "size": {"value": 130},
              "stroke": {
                "value": "#4682b4"
              },
              "tooltip": {
                "signal": "datum"
              },
              "fill": {
                "scale": "color",
                "field": "finalParty"
              }
            }
          }
        }
      ]
    }

     

    This is the updated Vega specification (note you need to change the setting in the Deneb visual to use the "Vega" provider instead of the default "Vega-Lite" provider)

     

  • Anonymous's avatar
    Anonymous
    Not applicable

    I want researching and I found that Deneb declarative custom visual can be use to achieve this.
    However, I have tried to use it but didn't work.
    I found some code in JSON but I don't know anything regarding Deneb and JSON. see below

    {
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "width": 550,
      "height": 300,
      "signals": [
        {"name": "dataLength", "update": "length(data('penguins'))"},
        {"name": "row0Radius", "value": 280},
        {"name": "row1Radius", "value": 260},
        {"name": "row2Radius", "value": 240},
        {"name": "row3Radius", "value": 220},
        {"name": "row4Radius", "value": 200},
        {"name": "row5Radius", "value": 180},
        {"name": "row6Radius", "value": 160},
        {"name": "row0Circ", "update": "PI*row0Radius"},
        {"name": "row1Circ", "update": "PI*row1Radius"},
        {"name": "row2Circ", "update": "PI*row2Radius"},
        {"name": "row3Circ", "update": "PI*row3Radius"},
        {"name": "row4Circ", "update": "PI*row4Radius"},
        {"name": "row5Circ", "update": "PI*row5Radius"},
        {"name": "row6Circ", "update": "PI*row6Radius"},
        {
          "name": "totalLength",
          "update": "row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ+row6Circ "
        }
      ],
      "data": [
        {
          "name": "penguins",
          "url": "data/penguins.json",
          "transform": [
            {"type": "project", "fields": ["Species", "Island"]},
            {
              "type": "window",
              "ops": ["row_number"],
              "fields": [null],
              "as": ["index"],
              "sort": {"field": "Island", "order": "ascending"}
            }
          ]
        },
        {
          "name": "placement",
          "transform": [
            {
              "type": "sequence",
              "start": 1,
              "stop": {"signal": "dataLength+1"},
              "as": "index"
            },
            {
              "type": "formula",
              "as": "wholeCirc",
              "expr": "totalLength/dataLength"
            },
            {
              "type": "window",
              "ops": ["sum"],
              "fields": ["wholeCirc"],
              "as": ["cumWholeCirc"]
            },
            {
              "type": "formula",
              "as": "row",
              "expr": "datum.cumWholeCirc <row0Circ?0:datum.cumWholeCirc <row0Circ+row1Circ?1:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ?2:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ?3:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ?4:datum.cumWholeCirc <row0Circ+row1Circ+row2Circ+row3Circ+row4Circ+row5Circ?5:6 "
            },
            {
              "type": "joinaggregate",
              "fields": ["Species"],
              "ops": ["count"],
              "groupby": ["row"],
              "as": ["rowCount"]
            },
            {
              "type": "formula",
              "as": "rowCirc",
              "expr": "datum.row==0?(row0Circ/(datum.rowCount-1)):datum.row==1?(row1Circ/(datum.rowCount-1)):datum.row==2?(row2Circ/(datum.rowCount-1)):datum.row==3?(row3Circ/(datum.rowCount-1)):datum.row==4?(row4Circ/(datum.rowCount-1)):datum.row==5?(row5Circ/(datum.rowCount-1)):datum.row==6?(row6Circ/(datum.rowCount-1)):0"
            },
            {
              "type": "window",
              "ops": ["sum"],
              "fields": ["rowCirc"],
              "groupby": ["row"],
              "sort": {"field": "index", "order": "descending"},
              "as": ["cumRowCirc"]
            },
            {
              "type": "formula",
              "as": "cumRowCircAct",
              "expr": "datum.cumRowCirc - datum.rowCirc "
            },
            {
              "type": "formula",
              "as": "theta",
              "expr": "datum.cumRowCircAct==0?0:datum.row==0?(datum.cumRowCircAct/row0Radius):datum.row==1?(datum.cumRowCircAct/row1Radius):datum.row==2?datum.cumRowCircAct/row2Radius:datum.row==3?datum.cumRowCircAct/row3Radius:datum.row==4?datum.cumRowCircAct/row4Radius:datum.row==5?datum.cumRowCircAct/row5Radius:datum.row==6?datum.cumRowCircAct/row6Radius:0"
            },
            {
              "type": "formula",
              "as": "x",
              "expr": "datum.row==0?row0Radius*cos(datum.theta):datum.row==1?row1Radius*cos(datum.theta):datum.row==2?row2Radius*cos(datum.theta):datum.row==3?row3Radius*cos(datum.theta):datum.row==4?row4Radius*cos(datum.theta):datum.row==5?row5Radius*cos(datum.theta):datum.row==6?row6Radius*cos(datum.theta):0"
            },
            {
              "type": "formula",
              "as": "y",
              "expr": "datum.row==0?row0Radius*sin(datum.theta):datum.row==1?row1Radius*sin(datum.theta):datum.row==2?row2Radius*sin(datum.theta):datum.row==3?row3Radius*sin(datum.theta):datum.row==4?row4Radius*sin(datum.theta):datum.row==5?row5Radius*sin(datum.theta):datum.row==6?row6Radius*sin(datum.theta):0"
            },
            {
              "type": "window",
              "sort": {"field": "theta", "order": "ascending"},
              "ops": ["row_number"],
              "fields": ["row_number"],
              "as": ["lookup"]
            },
            {
              "type": "lookup",
              "from": "penguins",
              "key": "index",
              "fields": ["lookup"],
              "values": ["Island"],
              "as": ["finalIsland"]
            }
          ]
        }
      ],
      "scales": [
        {
          "name": "x",
          "type": "linear",
          "round": true,
          "nice": true,
          "zero": true,
          "domain": {"field": "x", "data": "placement"},
          "range": "width"
        },
        {
          "name": "y",
          "type": "linear",
          "round": true,
          "nice": true,
          "zero": true,
          "domain": {"field": "y", "data": "placement"},
          "range": "height"
        },
        {
          "name": "color",
          "type": "ordinal",
          "domain": {"data": "placement", "field": "finalIsland"},
          "range": {"scheme": "category10"}
        }
      ],
      "marks": [
        {
          "name": "marks",
          "type": "symbol",
          "from": {"data": "placement"},
          "encode": {
            "update": {
              "x": {"scale": "x", "field": "x"},
              "y": {"scale": "y", "field": "y"},
              "shape": {"value": "circle"},
              "size": {"value": 130},
              "stroke": {"value": "#4682b4"},
              "tooltip": {"signal": "datum"},
              "fill": {"scale": "color", "field": "finalIsland"}
            }
          }
        }
      ]
    }

     This code was shared but I don't know how to reference my data and the column and measure I'm using.
    My data is Poll and the field (Party ) and measure (Seat Allocated).
    Please can someone help me out with the Deneb and code above to reference dataset and column and measure.

  • v-henryk-mstf's avatar
    v-henryk-mstf
    Community Support

    Hi Anonymous ,

     

    There does not seem to be a similar visual object in powerbi. What are your specific needs and maybe there is some other visual object that can replace it.

     

    Looking forward to your reply.


    Best Regards,
    Henry

     

  • KerKol's avatar
    KerKol
    Power Participant

    Hi there, Does the visual need to be curved? There may be a waffle template that will be easier to use.  If there are always the same amount of seats, there might be a lower code solution, such as using Synoptic Panel, Pureviz or Visio diagram

    • Anonymous's avatar
      Anonymous
      Not applicable

      KerKol v-henryk-mstf I wanted it to be curve but if there is other alternative visual please share with me. It is same number of seat every time.