vega / vega-lite

A concise grammar of interactive graphics, built on Vega.
https://vega.github.io/vega-lite/
BSD 3-Clause "New" or "Revised" License
4.66k stars 607 forks source link

resolve within a facet leads to Unrecognized scale name #4373

Open jakevdp opened 5 years ago

jakevdp commented 5 years ago

The following spec leads to an error (editor link)

Error: Unrecognized scale name: "child_layer_0_y"
{
  "data": {
    "url": "https://vega.github.io/vega-datasets/data/seattle-weather.csv"
  },
  "facet": {
    "column": {
      "field": "weather",
      "type": "nominal"
    }
  },
  "spec": {
    "layer": [
      {
        "encoding": {
          "x": {
            "field": "date",
            "timeUnit": "month",
            "type": "temporal"
          },
          "y": {
            "aggregate": "mean",
            "field": "temp_max",
            "type": "quantitative"
          }
        },
        "mark": {
          "color": "salmon",
          "type": "line"
        }
      },
      {
        "encoding": {
          "x": {
            "field": "date",
            "timeUnit": "month",
            "type": "temporal"
          },
          "y": {
            "aggregate": "mean",
            "field": "precipitation",
            "type": "quantitative"
          }
        },
        "mark": {
          "color": "steelblue",
          "type": "line"
        }
      }
    ],
    "resolve": {
      "scale": {
        "y": "independent"
      }
    }
  }
}

What I expect is that it would behave just like the following spec, except with independent y axis within each facet:

{
  "data": {
    "url": "https://vega.github.io/vega-datasets/data/seattle-weather.csv"
  },
  "facet": {
    "column": {
      "field": "weather",
      "type": "nominal"
    }
  },
  "spec": {
    "layer": [
      {
        "encoding": {
          "x": {
            "field": "date",
            "timeUnit": "month",
            "type": "temporal"
          },
          "y": {
            "aggregate": "mean",
            "field": "temp_max",
            "type": "quantitative"
          }
        },
        "mark": {
          "color": "salmon",
          "type": "line"
        }
      },
      {
        "encoding": {
          "x": {
            "field": "date",
            "timeUnit": "month",
            "type": "temporal"
          },
          "y": {
            "aggregate": "mean",
            "field": "precipitation",
            "type": "quantitative"
          }
        },
        "mark": {
          "color": "steelblue",
          "type": "line"
        }
      }
    ]
  }
}

(editor link) visualization 18

Related to https://stackoverflow.com/questions/53787262/vega-lite-independent-scale-with-multiple-layers-and-facet

domoritz commented 5 years ago

This is a bug. Thanks for the report!

domoritz commented 5 years ago

Ahh, so the problem is that the scales are defined inside each cell (which makes sense since they should be independent) but the header is defined outside and references a wrong scale.

domoritz commented 5 years ago

Hmm, I wonder why Vega-Lite does not automatically also make the axes independent.

domoritz commented 5 years ago

Something is wrong with layers inside facet. With just facet, it works.

{
  "data": {
    "url": "https://vega.github.io/vega-datasets/data/seattle-weather.csv"
  },
  "facet": {
    "column": {
      "field": "weather",
      "type": "nominal"
    }
  },
  "spec": {
    "encoding": {
      "x": {
        "field": "date",
        "timeUnit": "month",
        "type": "temporal"
      },
      "y": {
        "aggregate": "mean",
        "field": "precipitation",
        "type": "quantitative"
      }
    },
    "mark": {
      "color": "steelblue",
      "type": "line"
    }
  },
  "resolve": {
    "scale": {
      "y": "independent"
    }
  }
}
domoritz commented 5 years ago

As soon as we use a layer, it breaks:

{
  "data": {
    "url": "https://vega.github.io/vega-datasets/data/seattle-weather.csv"
  },
  "facet": {
    "column": {
      "field": "weather",
      "type": "nominal"
    }
  },
  "spec": {
    "layer": [{
      "encoding": {
        "x": {
          "field": "date",
          "timeUnit": "month",
          "type": "temporal"
        },
        "y": {
          "aggregate": "mean",
          "field": "precipitation",
          "type": "quantitative"
        }
      },
      "mark": {
        "color": "steelblue",
        "type": "line"
      }
    }],
    "resolve": {
      "scale": {
        "y": "independent"
      }
    }
  }
}
domoritz commented 5 years ago

Ahh, what you want is this (move the resolve one up).

{
  "data": {
    "url": "https://vega.github.io/vega-datasets/data/seattle-weather.csv"
  },
  "facet": {
    "column": {
      "field": "weather",
      "type": "nominal"
    }
  },
  "spec": {
    "layer": [
      {
        "encoding": {
          "x": {
            "field": "date",
            "timeUnit": "month",
            "type": "temporal"
          },
          "y": {
            "aggregate": "mean",
            "field": "temp_max",
            "type": "quantitative"
          }
        },
        "mark": {
          "color": "salmon",
          "type": "line"
        }
      },
      {
        "encoding": {
          "x": {
            "field": "date",
            "timeUnit": "month",
            "type": "temporal"
          },
          "y": {
            "aggregate": "mean",
            "field": "precipitation",
            "type": "quantitative"
          }
        },
        "mark": {
          "color": "steelblue",
          "type": "line"
        }
      }
    ]
  },
  "resolve": {
    "scale": {
      "y": "independent"
    }
  }
}

@jakevdp Your original spec would result in dual-axis charts for each facet. I don't think we should crash but at least we know what the right spec is.

domoritz commented 5 years ago

I don't think I really want to support faceted dual-axis charts so I'm inclined to just add a warning and drop the resolve in the original spec.

@kanitw @arvind what do you think?

jakevdp commented 5 years ago

@jakevdp Your original spec would result in dual-axis charts for each facet.

As I read it, that was the intent of the person asking the SO question.

domoritz commented 5 years ago

I see. Maybe it's not too hard to support it. It just wasn't one of the things I had tested when I wrote the resolve code.

jakevdp commented 5 years ago

Perhaps an hconcat + filter would be a good workaround? I haven't checked if that works.

jakevdp commented 5 years ago

Yeah, the concat workaround is fine here: vega editor

xujiboy commented 4 years ago

I don't think I really want to support faceted dual-axis charts so I'm inclined to just add a warning and drop the resolve in the original spec.

May I know if this decision has remain unchanged? Will faceted dual axis charts be supported in the future?

domoritz commented 4 years ago

Will faceted dual axis charts be supported in the future?

Yes, after the 4.0 release, I plan to spend some time on the dataflow code to fix issues like this. If anyone wants to help, please do.

tbui-isgn commented 4 years ago

[Summary: Got some of the goals ticked, but still not quite the graph that I'm after]

I managed to get the separate scales for each axis working for the 2 separate marks while keeping them in sync across all facets: visualization

The trick is to specify 2 levels of resolve separately, one "inside" the spec of the facet (i.e. at the same level as the layer) and the other one "outside" (i.e. same level with) the spec of the facet:

image

Here is the full code:

{
    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
    "data":{
        "url": "data/cars.json"
    },
    "facet":{
        "column": {
            "field":"Origin",
            "type": "nominal"
        }
    },
    "spec":{
        "layer": [
            {
                "mark": {
                    "type": "bar",
                    "clip": true,
                    "tooltip": true
                },
                "encoding": {

                    "x": {
                        "field": "Cylinders",
                        "type": "ordinal"
                    },
                    "y": {
                        "field": "Acceleration",
                        "type": "quantitative",
                        "aggregate":"average",
                        "axis": {
                            "title": "Acceleration",
                            "orient": "left"
                        }
                    },
                    "color": {
                        "field": "Cylinders",
                        "type": "nominal",
                        "legend":null
                    }
                }
            },
            {
                "mark": {
                    "type": "line",
                    "clip": true,
                    "color":"#ffde25",
                    "tooltip": true
                },
                "encoding": {
                    "x": {
                        "field": "Cylinders",
                        "type": "ordinal"
                    },
                    "y": {
                        "field": "Weight_in_lbs",
                        "type": "quantitative",
                        "aggregate":"average",
                        "axis": {
                            "title": "Weight (lbs)",
                            "orient": "right"
                        }
                    }

                }
            }
        ],
        "resolve": {
            "scale": {"y": "independent"}
        }
    },
    "resolve": {
        "scale": {"y": "shared"},
        "axis": {"y": "independent"}
    }

}

So it sort of works, but it is still not quite the right graph.

Would anyone have any idea on how to keep scales of the mark independent but have the axis shared? (i.e. what I want is similar to the graph I already shown above, but I only want 1 "Acceleration" axis on the left and 1 "Weight" axis on the right of the main plot area which contains all of the column facets)

I already tried to set the "axis" option of the outer "resolve" to be {"y": "shared"}, but it results in an error: Error: Unrecognized scale name: "child_layer_0_y"

If that is not possible at this stage, then I hope what I listed above helps demonstrate the problem with this bug a little bit clearer.

Any help would be appreciated.

Thanks.

camtr0n commented 2 weeks ago

Just want to chime in here that this last comment really does a great job at a work-around but we are forced to choose between two sub-optimal implementations:

The comment above, for me produces the best outcome with my data, seen here with independent scales in each graphic but also having independent axes repeated everywhere: CleanShot 2024-10-01 at 18 12 37

As opposed to the original suggestion of just moving the resolve to the outer layer where both y-scales are shared and the row of each facet also shares axes (and since the scales are shared I'm forced to use 8,000% making that layer unreadable): CleanShot 2024-10-01 at 18 16 37

That is, CleanShot 2024-10-01 at 18 14 19 VS CleanShot 2024-10-01 at 18 21 15

What it really seems like we need to work is this:

         "resolve": {
            "scale": {"y": "independent"}
        }
    },
    "resolve": {
        "scale": {"y": "shared"},
        "axis": {"y": "shared"}
    }

But this breaks rendering still.

Any chance we can get this addressed. It would be much cleaner to be able to share axes across the facet while having independent scales in each graphic. I have this use-case all the time 😃