Skip to content

facets with descrete values (e.g. geom_bar) does not work #196

@jankatins

Description

@jankatins

geom_bar uses arbitrary numbers as x axis (so making a bar plot where '3' has two values in the dataset does not mean that the bar is on "3" but it starts at 0.2). This fails when each facet has different values, they are not arranged in similar ways: 1,2,3 - 1,3,4 - 1,4,5 -> all have their bars at 0.2, 1.2, 1,3 (real x axis, not labels shown).

This means that that when the labels are removed from the subplots during faceting, you neither can see what the real labels are for each bar, nor have gaps where there are no values (second facet -> there should be a gap at '2'). It gets worse as the current faceting code removes the tick labels and reorganizes them for all facets and so they get the names of the position (which is 0.2, 1.2, 2.2, ...) and the grid is not anymore nicely under the bar.

Code to see the mess:

def _build_testing_df():
    df = pd.DataFrame({
        "x": np.arange(0, 10),
        "y": np.arange(0, 10),
        "z": np.arange(0, 10),
        "a": [1,1,1,1,1,2,2,2,3,3]
    })

    df['facets'] = np.where(df.x > 4, 'over', 'under')
    df['facets2'] = np.where((df.x % 2) == 0, 'even', 'uneven')
    return df

@cleanup
def test_facet_grid_descrete():
    df = _build_testing_df()
    gg = ggplot(aes(x='a'), data=df)
    assert_same_ggplot(gg + geom_bar() + facet_grid(x="facets", y="facets2"),
                       "faceting_grid_descrete")

@cleanup
def test_facet_wrap_descrete():
    df = _build_testing_df()
    gg = ggplot(aes(x='a'), data=df)
    assert_same_ggplot(gg + geom_bar() + facet_wrap(x="facets"), "faceting_wrap_descrete")

A a short term measure, I will add a warning at draw() time if faceting and geom_bar are used together.

Longterm I think this needs some more thought, as the current system is designed so that each facet does not know the properties of all the other facets but in this case we would need to compute the labels beforehand and use them at all individual facets. If we do that it's proably best to turn that around for all types. An Idea could be to add a new method to all geoms which would do the necessary data transforms, so faceting would be:

for geom in geoms:
   geom.do_faceting_transforms(...)
[old facets code, but pass in the faceting "hints"/transforms from above]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions