17

How do I get the internally created colorbar instance of a plot created by pandas.DataFrame.plot?

Here is an example for generating a colored scatter plot:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import itertools as it

# [ (0,0), (0,1), ..., (9,9) ]
xy_positions = list( it.product( range(10), range(10) ) )

df = pd.DataFrame( xy_positions, columns=['x','y'] )

# draw 100 floats
df['score'] = np.random.random( 100 )

ax = df.plot( kind='scatter',
              x='x',
              y='y',
              c='score',
              s=500)
ax.set_xlim( [-0.5,9.5] )
ax.set_ylim( [-0.5,9.5] )

plt.show()

which gives me a figure like this: enter image description here

How do I get the colorbar instance in order to manipulate it, for instance for changing the label or setting the ticks?

3 Answers 3

24

pandas does not return the axis for the colorbar, therefore we have to locate it:

1st, let's get the figure instance: i.e., use plt.gcf()

In [61]:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import itertools as it

# [ (0,0), (0,1), ..., (9,9) ]
xy_positions = list( it.product( range(10), range(10) ) )

df = pd.DataFrame( xy_positions, columns=['x','y'] )

# draw 100 floats
df['score'] = np.random.random( 100 )

ax = df.plot( kind='scatter',
              x='x',
              y='y',
              c='score',
              s=500)
ax.set_xlim( [-0.5,9.5] )
ax.set_ylim( [-0.5,9.5] )

f = plt.gcf()

2, how many axes does this figure have?

In [62]:

f.get_axes()
Out[62]:
[<matplotlib.axes._subplots.AxesSubplot at 0x120a4d450>,
 <matplotlib.axes._subplots.AxesSubplot at 0x120ad0050>]

3, The first axes (that is, the first one created), contains the plot

In [63]:

ax
Out[63]:
<matplotlib.axes._subplots.AxesSubplot at 0x120a4d450>

4, Therefore, the second axis is the colorbar axes

In [64]:

cax = f.get_axes()[1]
#and we can modify it, i.e.:
cax.set_ylabel('test')
Sign up to request clarification or add additional context in comments.

4 Comments

Ok, that gives me the axes where probably the colorbar is located. But how can I be sure that this is the right axes? I know in my setting that the second one in the axes list is my colorbar.
I don't think there is a easy way to identify colorbar axis when you have a complex figure containing a lot more axis (rather than just 2 in this case). You can identify colorbar axes by checking if the axis contains a matplotlib.collections.QuadMesh as one of its children (colorbar axis will have it), which is the color gradient. However, this is a unsafe hack as matplotlib.collections.QuadMesh may also appear in other types of plot. So I think it is better to figure out the order of creation of the axes and pick the colorbar axis(axes) that way.
Would be nice for the answer also to specify how to set the ticks. At this time, calling cax.set_yticks(i) will generate a warning rather than set the ticks, so the answer does not cover the specific challenges called out in the question.
After trying to wrestle with the colorbar for years this is easily one of the most satisfying and straightforward approaches I've ever encountered.
2

It's not quite the same but you could just plot using matplotlib:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import itertools as it

# [ (0,0), (0,1), ..., (9,9) ]
xy_positions = list( it.product( range(10), range(10) ) )

df = pd.DataFrame( xy_positions, columns=['x','y'] )

# draw 100 floats
df['score'] = np.random.random( 100 )

fig = plt.figure()
ax = fig.add_subplot(111)

s = ax.scatter(df.x, df.y, c=df.score, s=500)
cb = plt.colorbar(s)
cb.set_label('desired_label')

ax.set_xlim( [-0.5,9.5] )
ax.set_ylim( [-0.5,9.5] )

plt.show()

3 Comments

yes, that is also possible but is loses the beauty of using the DataFrame directly.
Maybe... but is ax = df.plot( kind='scatter', x='x', y='y', c='score', s=500) really more direct than s = ax.scatter(df.x, df.y, c=df.score, s=500)? I guess I prefer this to hunting around for the correct axes ;-)
Probably, using matplotlib directly has more advantages, especially if you want to use and modify the axes later.
1

To answer the original question: you can set colorbar=False and generate it separately. It needs a "mappable", i.e. a matplotlib object which contains colormap information. Here, it are the scatter dots stored in ax.collections[0]. With the return value of cbar = plt.colorbar(...) you get access to the colorbar and its ax.

import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import pandas as pd
import numpy as np

# [ (0,0), (0,1), ..., (9,9) ]
df = pd.DataFrame({'x': np.repeat(range(10), 10), 'y': np.tile(range(10), 10)})

# draw 100 floats
df['score'] = np.random.random(100)

ax = df.plot(kind='scatter',
             x='x',
             y='y',
             c='score',
             s=500,
             cmap='RdYlGn',
             vmin=0,
             vmax=1,
             colorbar=False)
ax.set_xlim([-0.5, 9.5])
ax.set_ylim([-0.5, 9.5])
ax.xaxis.set_major_locator(MultipleLocator(1))
ax.yaxis.set_major_locator(MultipleLocator(1))
cbar = plt.colorbar(ax.collections[0], ax=ax)
cbar.set_ticks([0, 0.5, 1])
cbar.set_ticklabels(['low', 'medium', 'high'])
cbar.ax.set_title('Score', ha='left')

plt.tight_layout()
plt.show()

access colorbar of pandas scatter plot

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.