cancel
Showing results for 
Search instead for 
Did you mean: 
Reply
Louis66
Resolver I
Resolver I

Bubbles on a 'timeline'

Hello to all,

 

I found this 'time line' (increasing numbers on the X-axis). For example, if the number is #351, it refers to number #349 and #351 - so a circle with a center at #351, radius = 2 :

Louis66_1-1675609573853.png

Any way to do this in Power BI ? Regards,

 

Louis

 

1 ACCEPTED SOLUTION

12 REPLIES 12
giammariam
Impactful Individual
Impactful Individual

Thanks @Louis66. If you run into issues getting it working in Deneb, let me know.



Madison Giammaria
Super User In Training‌ 😄
LinkedIn
ppm1
Solution Sage
Solution Sage

That should be possible with the Deneb visual. Provide some sample data and describe the logic of the visual a little more (i.e., how the size and position of each circle is defined), and someone here may try it out and provide a "spec" for you.

 

Declarative Visualization in Power BI | Deneb (deneb-viz.github.io)

 

Pat

 

Microsoft Employee

Hello Pat, my file is Excel, like this :

1 : no circle

2 : no circle

3 : no circle

4 : circle of radius 2 (circle goes from 2 to 6)

5 : no circle

6 : circle of radius 3 (circle goes from 3 to 9) & circle of radius 5 (circle goes from 1 to 11)

7...

 

There could ultimately be a lot of circles !

 

Regards,

 

Louis

giammariam
Impactful Individual
Impactful Individual

@Louis66, if you could provide a sanitized .pbix with data, I'd be happy to give this a shot in Deneb. See the below link on best ways to provide files/data:

How to provide sample data in the Power BI Forum - Microsoft Power BI Community



Madison Giammaria
Super User In Training‌ 😄
LinkedIn

1    
2    
3    
42   
5    
635  
7    
81   
9    
102347

 

How the circles are rendered makes sense to me. What I'm having a bit of trouble on is understanding what determines the length of the color bars. I get that the color of the bar corresponds and the color of the circle corresponds to a number on the x-axis.



Madison Giammaria
Super User In Training‌ 😄
LinkedIn

Well I don't quite know about the color bars - I am more interested in the circles for now...

giammariam
Impactful Individual
Impactful Individual

Hey @Louis66 , still looking into this. I got pretty close, but ran out of time. Will try to get back with a solution ASAP



Madison Giammaria
Super User In Training‌ 😄
LinkedIn

Hello,

 

No problem - I am not in a hurry,

 

Louis

giammariam
Impactful Individual
Impactful Individual

Hey @Louis66. Here's my spin on the circle timeline. Now this one was way trickier than I thought it'd be. I'm sure someone out there could find a better implementation; I had to do some workarounds to get it to work (e.g. use a rect mark instead of an arc or circle). You'll also need to transform your data before putting it into Deneb.

Take a look and let me know your thoughts. If this meets the requirement, consider marking this as the solution.

giammariam_1-1676062021529.png

 


Gist: https://vega.github.io/editor/#/gist/540669549e03f852075e5fcac91f16c2/spec.json
Spec:

 

 

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "params": [
    {"name": "min_adj_pos", "expr": "data('data_0')[0]['min_adj_pos']"},
    {"name": "max_adj_pos", "expr": "data('data_0')[0]['max_adj_pos']"},
    {"name": "color_scheme", "expr": "'tableau20'"},
    {
      "name": "pill_path",
      "expr": "'m 64.920826,87.413086 h 92.524964 c 14.1599,0 25.55938,14.249354 25.55938,31.949234 0,17.69986 -11.39948,31.94922 -25.55938,31.94922 H 64.920826 c -14.159896,0 -25.55938,-14.24936 -25.55938,-31.94922 0,-17.69988 11.399484,-31.949234 25.55938,-31.949234 z'"
    },
    {"name": "pill_xOffset", "expr": "-33"},
    {"name": "pill_yOffset", "expr": "-36"}
  ],
  "data": {
    "name": "dataset",
    "values": [
      {"index": 1, "r": 0},
      {"index": 2, "r": 0},
      {"index": 3, "r": 2},
      {"index": 4, "r": 0},
      {"index": 5, "r": 3},
      {"index": 6, "r": 0},
      {"index": 6, "r": 1},
      {"index": 6, "r": 4},
      {"index": 7, "r": 5},
      {"index": 8, "r": 0},
      {"index": 9, "r": 0},
      {"index": 10, "r": 2},
      {"index": 10, "r": 4},
      {"index": 11, "r": 7},
      {"index": 12, "r": 0}
    ]
  },
  "transform": [
    {
      "window": [{"op": "dense_rank", "as": "index_dr"}],
      "sort": [{"field": "index"}]
    },
    {
      "calculate": "datum['r']<= 0 ? 0 : datum['index']-datum['r']",
      "as": "adj_min_pos"
    },
    {
      "calculate": "datum['r']<= 0 ? 0 : datum['index']+datum['r']",
      "as": "adj_max_pos"
    },
    {
      "joinaggregate": [
        {"op": "min", "field": "adj_min_pos", "as": "min_adj_pos"},
        {"op": "max", "field": "adj_max_pos", "as": "max_adj_pos"}
      ]
    },
    {
      "calculate": "(datum['max_adj_pos']-datum['min_adj_pos'])/2",
      "as": "median_adj_pos"
    }
  ],
  "spacing": 0,
  "vconcat": [
    {
      "width": 800,
      "height": 800,
      "encoding": {
        "x": {
          "field": "index",
          "type": "quantitative",
          "scale": {
            "domain": [{"expr": "min_adj_pos"}, {"expr": "max_adj_pos"}]
          },
          "axis": null
        },
        "y": {
          "field": "index",
          "type": "quantitative",
          "scale": {
            "domain": [{"expr": "min_adj_pos"}, {"expr": "max_adj_pos"}]
          },
          "axis": {"tickCount": {"expr": "max_adj_pos-min_adj_pos"}}
        }
      },
      "layer": [
        {
          "encoding": {
            "color": {
              "field": "index",
              "scale": {"scheme": {"expr": "color_scheme"}},
              "legend": null
            }
          },
          "transform": [
            {"calculate": "width", "as": "width"},
            {"calculate": "datum['median_adj_pos']-datum['r']", "as": "y"},
            {"calculate": "datum['median_adj_pos']+datum['r']", "as": "y2"}
          ],
          "layer": [
            {
              "description": "circles",
              "mark": {
                "type": "rect",
                "opacity": 1,
                "cornerRadius": 9000000000,
                "strokeWidth": 1,
                "fillOpacity": 0
              },
              "encoding": {
                "stroke": {
                  "field": "index",
                  "scale": {"scheme": {"expr": "color_scheme"}},
                  "legend": null
                },
                "x": {"field": "adj_min_pos", "type": "quantitative"},
                "x2": {"field": "adj_max_pos"},
                "y": {"field": "y", "type": "quantitative", "axis": null},
                "y2": {"field": "y2"}
              }
            },
            {
              "layer": [
                {
                  "transform": [
                    {"filter": "datum['r']>0"},
                    {
                      "window": [
                        {"op": "dense_rank", "as": "dr_index_updated"}
                      ],
                      "sort": [{"field": "index"}]
                    },
                    {
                      "calculate": "datum['dr_index_updated']%2",
                      "as": "alternate"
                    },
                    {
                      "calculate": "datum['alternate'] == 1 ? datum['y'] : datum['y2']",
                      "as": "y"
                    }
                  ],
                  "description": "vertical lines",
                  "mark": {
                    "type": "rule",
                    "opacity": 1,
                    "strokeWidth": 1,
                    "fillOpacity": 0,
                    "strokeDash": [5, 5]
                  },
                  "encoding": {
                    "stroke": {
                      "field": "index",
                      "scale": {"scheme": {"expr": "color_scheme"}},
                      "legend": null
                    },
                    "x": {"field": "index", "type": "quantitative"},
                    "x2": {"field": "index"},
                    "y": {"field": "y", "type": "quantitative", "axis": null},
                    "y2": {"field": "median_adj_pos"}
                  }
                },
                {
                  "description": "line label background (color)",
                  "transform": [{"filter": "datum['r']>0"}],
                  "mark": {
                    "type": "point",
                    "shape": {"expr": "pill_path"},
                    "xOffset": {"expr": "pill_xOffset"},
                    "yOffset": {"expr": "pill_yOffset"}
                  },
                  "encoding": {
                    "x": {"field": "index", "type": "quantitative"},
                    "y": {
                      "field": "median_adj_pos",
                      "type": "quantitative",
                      "axis": null
                    },
                    "size": {"value": 0.35}
                  }
                },
                {
                  "description": "line label background (white)",
                  "transform": [{"filter": "datum['r']==0"}],
                  "mark": {
                    "type": "point",
                    "shape": {"expr": "pill_path"},
                    "xOffset": {"expr": "pill_xOffset"},
                    "yOffset": {"expr": "pill_yOffset"}
                  },
                  "encoding": {
                    "x": {"field": "index", "type": "quantitative"},
                    "y": {
                      "field": "median_adj_pos",
                      "type": "quantitative",
                      "axis": null
                    },
                    "size": {"value": 0.35},
                    "color": {"value": "white"}
                  }
                },
                {
                  "description": "line labels",
                  "transform": [
                    {
                      "window": [{"op": "row_number", "as": "dr_index_rn"}],
                      "groupby": ["index"]
                    },
                    {"filter": "datum['dr_index_rn'] == 1"}
                  ],
                  "mark": {
                    "type": "text",
                    "opacity": 1,
                    "stroke": "gray",
                    "filled": false,
                    "strokeOffset": {"expr": "1"},
                    "fontSize": 18,
                    "align": "center"
                  },
                  "encoding": {
                    "text": {"field": "index"},
                    "x": {"field": "index", "type": "quantitative"},
                    "y": {
                      "field": "median_adj_pos",
                      "type": "quantitative",
                      "axis": null
                    }
                  }
                }
              ],
              "resolve": {"legend": {"color": "independent"}}
            }
          ]
        }
      ]
    }
  ],
  "resolve": {"axis": {"x": "shared"}, "scale": {"x": "shared"}}
}

 

 

 

@dm-p, would love to get your thoughts on how you'd implement this one. Probably would be more suitable for Vega instead of Vega-Lite.






Madison Giammaria
Super User In Training‌ 😄
LinkedIn

Interactive version: 
https://vega.github.io/editor/#/gist/813b7398a99f652252b5cdf2c215b7c2/spec.json

 

giphy



Madison Giammaria
Super User In Training‌ 😄
LinkedIn

Djeez - this is something ! Good job !

Helpful resources

Announcements
May 2023 update

Power BI May 2023 Update

Find out more about the May 2023 update.

Submit your Data Story

Data Stories Gallery

Share your Data Story with the Community in the Data Stories Gallery.

Top Solution Authors