1

I have a dataframe which looks like this:

  Team  Minute  Type
   148      12     1
   148      22     1
   143      27     1
   148      29     1
   143      32     1
   143      32     1

I created a joyplot using the Python library joypy

fig, axes = joypy.joyplot(df, by="Team", column="Minute", figsize =(10,16), x_range = [0,94], linewidth = 1, colormap=plt.cm.viridis)

Which gave me this plot:

enter image description here

All Good. However, the colourmap is meaningless now so I am trying to color the plots according to a second dataframe - which is the sum of Type for all the teams.

To do that, I created a norm, and a colourmap using these lines:

norm = plt.Normalize(group_df["Type"].min(), group_df["Type"].max())
cmap = plt.cm.viridis
sm = matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm)
ar = np.array(group_df["Type"])
Cm = cmap(norm(ar))
sm.set_array([])

Here's where the problem arose as I can't figure out how to change the color of the joyplots. I tried a couple of approaches:

  1. I tried to pass this Cm as the colormap argument. However, that threw up an error - typeerror 'numpy.ndarray' object is not callable

  2. I tried to use a for loop over the axes and Cm -

for col, ax in zip(Cm, axes):
    ax.set_facecolor(col)
    #ax.patch.set_facecolor(col) ##Also tried this; didn't change anything

How can I get greater control over the colours of the joyplot and change them around? Any help would be appreciated.

MCVE

Sample of the csv file I'm reading in(Actual shape of dataframe is (4453,2)):

      Team  Minute
0      148       5
1      148       5
2      148      11
3      148      11
4      148      12
5      148      22
6      143      27

My code:

df = pd.read_csv(r"path")

##getting the sum for every team - total of 20 teams
group_df = df.groupby(["Team"]).size().to_frame("Count").reset_index()
  
df["Minute"] = pd.to_numeric(df["Minute"])

##Trying to create a colormap 
norm = plt.Normalize(group_df["Count"].min(), group_df["Count"].max())
cmap = plt.cm.viridis
sm = matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm)
ar = np.array(group_df["Count"])
Cm = cmap(norm(ar))
sm.set_array([])


fig, axes = joypy.joyplot(df, by="Team", column="Minute", figsize =(10,16), x_range = [0,94], colormap = plt.cm.viridis)

I want to color every subplot in the plot by the total count of the team from the group_df["Count"] values. Currently, the colormap is just uniform and not according to the total value. The picture above is what's produced.

Marcus Campbell
  • 2,746
  • 4
  • 22
  • 36
Abhishek
  • 553
  • 2
  • 9
  • 26
  • You might be successful in providing `joyplot` with a list of colors instead of a colormap. If not, creating this kind of plot might be easier be done manually where you have full control over everything, not only colors. – ImportanceOfBeingErnest Jun 26 '19 at 19:14
  • Thank you again, that looks like it might work out. How do I create this kind of plot manually? I thought Joypy was the only package available for creating joyplots. I'm still curious though. Why does ax.set_facecolor() not work; is that a bug? – Abhishek Jun 27 '19 at 02:03
  • 1
    For example: [here](https://stackoverflow.com/questions/54729039/stacked-density-plots-with-pandas-and-seaborn/54729242#54729242) – ImportanceOfBeingErnest Jun 27 '19 at 02:06
  • `ax.set_facecolor()` sets the color of the axes, so it wouldn't help. The reason you don't see it have any effect is that the axes is turned off anyways. I can help you more if you provided a running example ([mcve], [How to make good reproducible pandas examples](https://stackoverflow.com/questions/20109391/how-to-make-good-reproducible-pandas-examples)) that I can modify. – ImportanceOfBeingErnest Jun 27 '19 at 02:45
  • I just did that, will this be okay? @ImportanceOfBeingErnest – Abhishek Jun 27 '19 at 03:29
  • If that returns the axes, how do I get a handle on the individual plots? – Abhishek Jun 27 '19 at 03:47
  • Passing a list of colours didn't work as there is no argument for that – Abhishek Jun 27 '19 at 07:16

1 Answers1

3

joypy fills the colors of the KDE curves sequentially from a colormap. So in order to have the colors match to a third variable you can supply a colormap which contains the colors in the order you need. This can be done using a ListedColormap.

import matplotlib
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(21)
import pandas as pd
import joypy

df = pd.DataFrame({"Team" : np.random.choice([143,148,159,167], size=200),
                   "Minute" : np.random.randint(0,100, size=200)})

##getting the sum for every team - total of 20 teams
group_df = df.groupby(["Team"]).size().to_frame("Count").reset_index()
print(group_df)



##Trying to create a colormap 
norm = plt.Normalize(group_df["Count"].min(), group_df["Count"].max())
ar = np.array(group_df["Count"])

original_cmap = plt.cm.viridis
cmap = matplotlib.colors.ListedColormap(original_cmap(norm(ar)))
sm = matplotlib.cm.ScalarMappable(cmap=original_cmap, norm=norm)
sm.set_array([])

fig, axes = joypy.joyplot(df, by="Team", column="Minute", x_range = [0,94], colormap = cmap)
fig.colorbar(sm, ax=axes, label="Count")

plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712