2

I am trying to add a continuous colorbar to a seaborn scatterplot (similar to the answers here and in here). For my purposes, I am building the scatterplot with a loop, and then trying to add the continuous colorbar, but I dont know what object to include as argument of fig.colorbar(). How would you do this?

import pandas as pd
import seaborn as sb
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)

df=pd.DataFrame(np.random.rand(2, 100), index=['S1','S2']).T
tars=np.random.choice([0,0.3,0.5,0.8,1], 100)
df=pd.concat([df,pd.Series(tars, name='group')],1)
colors = matplotlib.cm.viridis(np.linspace(0,1,len(pd.unique(tars))))

fig = plt.figure(figsize = (10,8), dpi=300)
ax = fig.add_subplot(1,1,1) 
targets=pd.unique(tars)
for target, color in zip(targets,colors):
    ...
    g=ax.scatter(
        df.loc[df.group==target, 'S1'], 
        df.loc[df.group==target, 'S2'],
        color = [color]
    )
fig.colorbar(g)
plt.show()

enter image description here

If I add ax.legend(targets) instead of fig.colorbar(g), the legend displays correctly but is categorical.

df=pd.DataFrame(np.random.rand(2, 100), index=['S1','S2']).T
tars=np.random.choice([0,0.3,0.5,0.8,1], 100)
df=pd.concat([df,pd.Series(tars, name='group')],1)

cmap=matplotlib.cm.gnuplot2
colors = cmap(np.linspace(0,1,len(pd.unique(tars))))

fig = plt.figure(figsize = (10,8), dpi=300)
ax = fig.add_subplot(1,1,1) 
targets=pd.unique(tars)
for target, color in zip(targets,colors):
    ...
    g=ax.scatter(
        df.loc[df.group==target, 'S1'], 
        df.loc[df.group==target, 'S2'],
        color = [color]
    )
ax.legend(targets)
plt.show()

enter image description here

Sos
  • 1,783
  • 2
  • 20
  • 46
  • Are the points in your example how they are supposed to look, or is it just to show where you want the colorbar? Since the color of the dots are not from the colorbar's colormap. I had a similar issue recently where I needed one colorbar for sets of points that used different colormap scales. Is that what you need too? – Francisca Concha-Ramírez Jul 09 '20 at 10:30
  • @FranciscaConcha-Ramírez thanks for your comment. The points were actually correct but not the colorbar. I have edited my post to make this clearer. – Sos Jul 09 '20 at 12:14
  • 1
    thanks for clarifying. I think this answer might be helpful: https://stackoverflow.com/a/14779462/2943652 – Francisca Concha-Ramírez Jul 09 '20 at 15:17
  • 1
    I'm very sorry. It was in response to another question. I deleted it. – r-beginners Jul 10 '20 at 02:42
  • @FranciscaConcha-Ramírez looking at this again, I have noticed that the dots were shown as expected, but not really. I had messed up and showed the screenshot of the fixed code but had kept the comments in the edited code chunks in my question. My apologies, you were right in asking about that. I have now edited my question as it should be. I kept the screenshots as they are qualitatively the same to what I get – Sos Jul 10 '20 at 12:23

2 Answers2

1

Thanks to this answer I could edit my code to show the continuous colorbar.

df=pd.DataFrame(np.random.rand(2, 100), index=['S1','S2']).T
tars=np.random.choice([0,0.3,0.5,0.8,1], 100)
df=pd.concat([df,pd.Series(tars, name='group')],1)

cmap=matplotlib.cm.viridis
colors = cmap(np.linspace(0,1,len(pd.unique(tars))))

fig = plt.figure(figsize = (10,8), dpi=300)
ax = fig.add_subplot(1,1,1) 
targets=pd.unique(tars)
for target, color in zip(targets,colors):
    g=ax.scatter(
        df.loc[df.group==target, 'S1'], 
        df.loc[df.group==target, 'S2'],
        color=[color]
    )

norm = plt.Normalize(np.min(tars), np.max(tars))
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
ax.figure.colorbar(sm)
plt.show()

enter image description here

Sos
  • 1,783
  • 2
  • 20
  • 46
  • 1
    Good job on finding the answer to your question. You've made a mistake in `Normalize()` where you have used `min()` twice, instead of `min()` and `max()`, hence the wrong scale of the colorbar – Diziet Asahi Jul 10 '20 at 13:50
0

I am not entirely sure to understand what you are trying to achieve with your for-loop.

Is this the output that you are looking for?

fig = plt.figure()
ax = fig.add_subplot(1,1,1) 
g = ax.scatter(df['S1'],df['S2'],c=df['group'],cmap='viridis')
cbar = fig.colorbar(g)
plt.show()

enter image description here

Diziet Asahi
  • 38,379
  • 7
  • 60
  • 75
  • Hi Diziet, that is true, that is the output I'd like to see. For my purposes I believe I have to use the loop as other things are being plotted and added to the axes there depending on `colors` and `targets`. I must say my post had messed up the `cmap` in the loop, and it should've showed a line that was commented giving `color=[color]` instead of `cmap = cmap=matplotlib.cm.gnuplot2`. – Sos Jul 10 '20 at 12:16