Repository: plotly/plotly.py

Issue:
Parallel categories not recognizing dimension columns
Data frame with two categorical columns and one numerical column being passed to `px.parallel_categories`. Only one column gets visualized, no matter what is passed to `dimensions`: a single column, two columns, or no columns.

Data types changed to `str` and `category`, but no change.

Data:

![px](https://user-images.githubusercontent.com/1219001/59059308-a48c1480-886c-11e9-91b8-52772e6656fd.PNG)

Code:

`px.parallel_categories(occupations_by_year, dimensions=['Main_jobs', 'Election year'], color = 'count')`

Result:

![px2](https://user-images.githubusercontent.com/1219001/59059317-a7870500-886c-11e9-8b91-7b49ce5a109c.PNG)

Python 3.6
plotly==3.10.0
plotly-express==0.3.0



Discussion:
How many unique values of `main_jobs` are there?
About 30 unique values. I was hoping to make each year a node in the chart
and the jobs the bands between them, a bit like a Sankey. Is this possible?

On Thu, Jun 6, 2019, 4:48 PM Nicolas Kruchten <notifications@github.com>
wrote:

> How many unique values of main_jobs are there?
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/plotly/plotly_express/issues/98?email_source=notifications&email_token=AAJJTOMGAKJHJALXRSHQCGTPZFZYBA5CNFSM4HVHS2J2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXEDXCQ#issuecomment-499661706>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAJJTONC4GQ72KJHUBPNAZLPZFZYBANCNFSM4HVHS2JQ>
> .
>

Yes, but I'll have to generalize the cutoff heuristic, which right now caps the number of values at 20 IIRC. This a little blunt for cases like this where you only have 2 dimensions. It's reasonably if you had e.g. 10 dimensions because in that case you might have up to 20^10 combinations :)
I have encountered this issue as well. I have four columns, one of which has ~30 categories. There are about 1100 unique combinations in the data, so not ridiculous, but the column with the 30 categories is left out of the plot.
I 2nd the desire to set the cutoff of number of categories. Like these charts but I've hit this roadblock and I think I was just barely over the cutoff limit. I'm ok to group my categories down to reduce complexity, but wish to have a little more flexibility in doing so.
I'll get this fixed in the next version :) I'll move this issue to the plotly.py repo to get it scheduled.
Same issue over here. It is an easy way to look for colinearity among categorical features. Please get it fixed.

**unique transmission_model : 19
unique model_family: 24**

![image](https://user-images.githubusercontent.com/3968323/72534391-7e444380-3855-11ea-85b1-73f92ed8ea9e.png)

![image](https://user-images.githubusercontent.com/3968323/72534457-987e2180-3855-11ea-8127-da9ff3fcf42f.png)


Python 3.5.6
Plotly 4.4.1


Resolving patch:
diff --git a/packages/python/plotly/plotly/express/_chart_types.py b/packages/python/plotly/plotly/express/_chart_types.py
--- a/packages/python/plotly/plotly/express/_chart_types.py
+++ b/packages/python/plotly/plotly/express/_chart_types.py
@@ -1205,6 +1205,7 @@ def parallel_categories(
     template=None,
     width=None,
     height=None,
+    dimensions_max_cardinality=50,
 ):
     """
     In a parallel categories (or parallel sets) plot, each row of
diff --git a/packages/python/plotly/plotly/express/_core.py b/packages/python/plotly/plotly/express/_core.py
--- a/packages/python/plotly/plotly/express/_core.py
+++ b/packages/python/plotly/plotly/express/_core.py
@@ -181,7 +181,9 @@ def make_trace_kwargs(args, trace_spec, g, mapping_labels, sizeref):
                 )
                 and (
                     trace_spec.constructor != go.Parcats
-                    or len(args["data_frame"][name].unique()) <= 20
+                    or (v is not None and name in v)
+                    or len(args["data_frame"][name].unique())
+                    <= args["dimensions_max_cardinality"]
                 )
             ]
             result["dimensions"] = [
diff --git a/packages/python/plotly/plotly/express/_doc.py b/packages/python/plotly/plotly/express/_doc.py
--- a/packages/python/plotly/plotly/express/_doc.py
+++ b/packages/python/plotly/plotly/express/_doc.py
@@ -106,6 +106,12 @@
         colref_list_desc,
         "Values from these columns are used for multidimensional visualization.",
     ],
+    dimensions_max_cardinality=[
+        "int (default 50)",
+        "When `dimensions` is `None` and `data_frame` is provided, "
+        "columns with more than this number of unique values are excluded from the output.",
+        "Not used when `dimensions` is passed.",
+    ],
     error_x=[
         colref_type,
         colref_desc,


Test patch:
diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py b/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py
--- a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py
+++ b/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py
@@ -139,3 +139,36 @@ def test_funnel():
         color=["0", "0", "0", "1", "1", "1"],
     )
     assert len(fig.data) == 2
+
+
+def test_parcats_dimensions_max():
+    df = px.data.tips()
+
+    # default behaviour
+    fig = px.parallel_categories(df)
+    assert [d.label for d in fig.data[0].dimensions] == [
+        "sex",
+        "smoker",
+        "day",
+        "time",
+        "size",
+    ]
+
+    # explicit subset of default
+    fig = px.parallel_categories(df, dimensions=["sex", "smoker", "day"])
+    assert [d.label for d in fig.data[0].dimensions] == ["sex", "smoker", "day"]
+
+    # shrinking max
+    fig = px.parallel_categories(df, dimensions_max_cardinality=4)
+    assert [d.label for d in fig.data[0].dimensions] == [
+        "sex",
+        "smoker",
+        "day",
+        "time",
+    ]
+
+    # explicit superset of default, violating the max
+    fig = px.parallel_categories(
+        df, dimensions=["sex", "smoker", "day", "size"], dimensions_max_cardinality=4
+    )
+    assert [d.label for d in fig.data[0].dimensions] == ["sex", "smoker", "day", "size"]