joelostblom
joelostblom

Reputation: 49054

Sorting a chart axis based on the dynamically updated axis order in another chart

In this VegaLite spec the y-axis order of the bottom-most barplot is updated as the data of that plot is filtered based on the selection in the scatter plot. How can I achieve the same resorting behavior for both the blue and orange bars in the top-most bar plot where I have layered the same barplot together with another chart?

I have tried toggling the axis between shared and independent and switching the order of the layer, but that didn't do it. Conceptually I can imagine using a calculate transform to define a new field that is based on the selection and used as the sort order key, but I can't figure out how to write this vega expression string.

enter image description here

Here is that Altair code if anyone prefers to solve it that way:

import altair as alt
import pandas as pd


data={
 'Term': ['algorithm','learning','learning','algorithm','algorithm','learning'],
 'Freq_x': [1330,1153,504.42,296.69,177.59,140.35],
 'Total': [1330, 1353,1353.7,1330.47,1330.47,1353.7],
 'Category': ['Default', 'Default', 'Topic1', 'Topic1', 'Topic2', 'Topic2'],
 'logprob': [30.0, 27.0, -5.116, -5.1418, -5.4112, -5.5271],
 'loglift': [30.0, 27.0, 0.0975, 0.0891, -0.1803, -0.3135],
 'saliency_ind': [0, 3, 76, 77, 181, 186],
 'x': [None,None,-0.0080,-0.0080,-0.0053,-0.0053],
 'y': [None,None,-0.0056,-0.0056, 0.0003,0.0003],
 'topics': [None,None, 1.0, 1.0, 2.0, 2.0],
 'cluster': [None,None, 1.0, 1.0, 1.0, 1.0],
 'Freq_y': [None,None,20.39,20.39,14.18,14.18]}

df=pd.DataFrame(data)

pts = alt.selection(type="single", fields=['Category'], empty='none')

points = alt.Chart(df).mark_circle().encode(
    x='mean(x)',
    y='mean(y)',
    size='Freq_y',
    detail='Category',
    color=alt.condition(pts, alt.value('#F28E2B'), alt.value('#4E79A7'))
).add_selection(pts)

bars = alt.Chart(df).mark_bar().encode(
    x='Freq_x',
    y=alt.Y('Term'),
)

bars2 = alt.Chart(df).mark_bar(color='#F28E2B').encode(
    x='Freq_x',
    y=alt.Y('Term', sort='-x'),
).transform_filter(
    pts
)

(points | (bars + bars2) & bars2)

Upvotes: 1

Views: 261

Answers (1)

wahab memon
wahab memon

Reputation: 2416

The issue with your spec was that in layers you performed filter transform which created a separate data for each layers. Sorting was working at each level of layer but since both the layers data were separate so each layer was getting sorted inpendently.

So instead of having a filter transform, I tried to manual filter using calculate transform and created a filtered_freq_x field which is later used on 2nd layer and performed sorting using this on window. So with this my data becomes same for both layers, just few fields were added and used.

Let me know if this works for you not. Below is the spec config and editor:

{
  "config": {"view": {"continuousWidth": 200, "continuousHeight": 300}},
  "hconcat": [
    {
      "mark": "circle",
      "encoding": {
        "color": {
          "condition": {"value": "#F28E2B", "selection": "selector046"},
          "value": "#4E79A7"
        },
        "detail": {"type": "nominal", "field": "Category"},
        "size": {"type": "quantitative", "field": "Freq_y"},
        "x": {"type": "quantitative", "aggregate": "mean", "field": "x"},
        "y": {"type": "quantitative", "aggregate": "mean", "field": "y"}
      },
      "selection": {
        "selector046": {
          "type": "single",
          "fields": ["Category"],
          "empty": "none"
        }
      }
    },
    {
      "vconcat": [
        {
          "transform": [
            {
              "joinaggregate": [
                {"field": "Freq_x", "op": "max", "as": "max_Fx"}
              ]
            },
            {
              "calculate": "selector046['Category'] ? selector046['Category'] : []",
              "as": "filterCategory"
            },
            {
              "calculate": "indexof(datum.filterCategory,datum['Category']) > -1 ? datum['Freq_x'] : null",
              "as": "filtered_Freq_x"
            },
            {
              "sort": [{"field": "filtered_Freq_x", "order": "descending"}],
              "window": [{"op": "rank", "as": "Sorted"}]
            }
          ],
          "height": 50,
          "layer": [
            {
              "mark": "bar",
              "encoding": {
                "x": {"type": "quantitative", "field": "Freq_x"},
                "y": {
                  "type": "nominal",
                  "field": "Term",
                  "sort": {"field": "Sorted"}
                }
              }
            },
            {
              "mark": {"type": "bar", "color": "#F28E2B"},
              "encoding": {
                "x": {"type": "quantitative", "field": "filtered_Freq_x"},
                "y": {
                  "type": "nominal",
                  "field": "Term",
                  "sort": {"field": "Sorted"}
                }
              }
            }
          ]
        },
        {
          "mark": {"type": "bar", "color": "#F28E2B"},
          "encoding": {
            "x": {"type": "quantitative", "field": "Freq_x"},
            "y": {"type": "nominal", "field": "Term", "sort": "-x"}
          },
          "transform": [{"filter": {"selection": "selector046"}}]
        }
      ]
    }
  ],
  "data": {"name": "data-d807cd22b94d04d6f1543201cfe5f45e"},
  "$schema": "https://vega.github.io/schema/vega-lite/v4.8.1.json",
  "datasets": {
    "data-d807cd22b94d04d6f1543201cfe5f45e": [
      {
        "Term": "algorithm",
        "Freq_x": 1330,
        "Total": 1330,
        "Category": "Default",
        "logprob": 30,
        "loglift": 30,
        "saliency_ind": 0,
        "x": null,
        "y": null,
        "topics": null,
        "cluster": null,
        "Freq_y": null
      },
      {
        "Term": "learning",
        "Freq_x": 1153,
        "Total": 1353,
        "Category": "Default",
        "logprob": 27,
        "loglift": 27,
        "saliency_ind": 3,
        "x": null,
        "y": null,
        "topics": null,
        "cluster": null,
        "Freq_y": null
      },
      {
        "Term": "learning",
        "Freq_x": 504.42,
        "Total": 1353.7,
        "Category": "Topic1",
        "logprob": -5.116,
        "loglift": 0.0975,
        "saliency_ind": 76,
        "x": -0.008,
        "y": -0.0056,
        "topics": 1,
        "cluster": 1,
        "Freq_y": 20.39
      },
      {
        "Term": "algorithm",
        "Freq_x": 296.69,
        "Total": 1330.47,
        "Category": "Topic1",
        "logprob": -5.1418,
        "loglift": 0.0891,
        "saliency_ind": 77,
        "x": -0.008,
        "y": -0.0056,
        "topics": 1,
        "cluster": 1,
        "Freq_y": 20.39
      },
      {
        "Term": "algorithm",
        "Freq_x": 177.59,
        "Total": 1330.47,
        "Category": "Topic2",
        "logprob": -5.4112,
        "loglift": -0.1803,
        "saliency_ind": 181,
        "x": -0.0053,
        "y": 0.0003,
        "topics": 2,
        "cluster": 1,
        "Freq_y": 14.18
      },
      {
        "Term": "learning",
        "Freq_x": 140.35,
        "Total": 1353.7,
        "Category": "Topic2",
        "logprob": -5.5271,
        "loglift": -0.3135,
        "saliency_ind": 186,
        "x": -0.0053,
        "y": 0.0003,
        "topics": 2,
        "cluster": 1,
        "Freq_y": 14.18
      }
    ]
  }
}

Upvotes: 1

Related Questions