Repository: plotly/plotly.py
Pull request: added: ignore facet args with empty dataset
Closes #3984 
## Code PR

- [x] I have read through the [contributing notes](https://github.com/plotly/plotly.py/blob/master/contributing.md) and understand the structure of the package. In particular, if my PR modifies code of `plotly.graph_objects`, my modifications concern the `codegen` files and not generated files.
- [x] I have added tests (if submitting a new feature or correcting a bug) or
  modified existing tests.
- [ ] For a new feature, I have added documentation examples in an existing or
  new tutorial notebook (please see the doc checklist as well).
- [x] I have added a CHANGELOG entry if fixing/changing/adding anything substantial.
- [ ] For a new feature or a change in behaviour, I have updated the relevant docstrings in the code to describe the feature or behaviour (please see the doc checklist as well).

Being brand new to plotly, I'm unsure of where to put a test for this, as the original issue relates to a `pandas.DataFrame`.

Problem statement:
plot empty dataframe fails if facet_col/row is specified
In most cases plotting with an empty data_frame works nicely, I mean, it shows a figure with no traces but with the good layout.
But if we specify a `facet_col` or `facet_row` it fails.

```python
import plotly.express as px
import pandas as pd
px.bar(
    pd.DataFrame(columns=['A', 'B', 'X']),
    x = 'A',
    y = 'X',
    facet_col = 'B'
)
```
I would expect the same result as if `facet_col` was None. As it is already the case for `animation_frame`

Hints from issue discussion:

Commit message: added: ignore facet args with empty dataset

Patch to review:
diff --git a/packages/python/plotly/plotly/express/_core.py b/packages/python/plotly/plotly/express/_core.py
index 437df83de7d..91d656515b2 100644
--- a/packages/python/plotly/plotly/express/_core.py
+++ b/packages/python/plotly/plotly/express/_core.py
@@ -1988,6 +1988,10 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
     layout_patch = layout_patch or {}
     apply_default_cascade(args)
 
+    # Ignore facet rows and columns when data frame is empty so as to prevent nrows/ncols equaling 0
+    if len(args["data_frame"]) == 0:
+        args["facet_row"] = args["facet_col"] = None
+
     args = build_dataframe(args, constructor)
     if constructor in [go.Treemap, go.Sunburst, go.Icicle] and args["path"] is not None:
         args = process_dataframe_hierarchy(args)


Code review comments:
diff_hunk: @@ -1988,6 +1988,10 @@ def make_figure(args, constructor, trace_patch=None, layout_patch=None):
     layout_patch = layout_patch or {}
     apply_default_cascade(args)
 
+    # Ignore facet rows and columns when data frame is empty so as to prevent nrows/ncols equaling 0
path: packages/python/plotly/plotly/express/_core.py
text: @user1:
This seems like a reasonable fix, but probably belongs near the bottom of the `infer_config` function, just so it's in roughly the same place as most of the other similar mutations of `args`.

While we're on this topic of empty data frames though, are there any other args that fail when the df length is 0? would be good to understand why these specifically fail and if it impacts other categorical-type attributes like `symbol` or somethinng. Maybe there could be a more generic fix?

@user1:
PS: thanks for the PR! :)

@author:
Ah yes, that makes sense. And you're very welcome. :)

I've moved it into `infer_config` for now, but I'll look into whether there could be a more generic solution.

@author:
So it looks like `facet_col` and `facet_row` both fail with an empty dataset because they are used in the computation of `ncols` and `nrows`:

https://github.com/plotly/plotly.py/blob/2b6ec1e16bebe260dfc673db869805f7ceb86e00/packages/python/plotly/plotly/express/_core.py#L2014-L2021

Neither `ncols` nor `nrows` can equal 0, hence the failure. As far as I can tell, nothing else in `args` effects either of the two in any other way.

To me, this seems like a fairly specific failure requiring a specific fix, but I'm still far from familiar with the codebase, so I could easily be wrong. :)