Matplotlib Colorbar for Scatter

matplotlib colorbar for scatter

From the matplotlib docs on scatter 1:

cmap is only used if c is an array of floats

So colorlist needs to be a list of floats rather than a list of tuples as you have it now.
plt.colorbar() wants a mappable object, like the CircleCollection that plt.scatter() returns.
vmin and vmax can then control the limits of your colorbar. Things outside vmin/vmax get the colors of the endpoints.

How does this work for you?

import matplotlib.pyplot as plt
cm = plt.cm.get_cmap('RdYlBu')
xy = range(20)
z = xy
sc = plt.scatter(xy, xy, c=z, vmin=0, vmax=20, s=35, cmap=cm)
plt.colorbar(sc)
plt.show()

Image Example

Add colorbar as legend to matplotlib scatterplot (multiple subplots, multiple scatters)

A colorbar needs a ScalarMappable as input. So if none of the things you create in your plot is suitable for that, you may create it yourself.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.cm import ScalarMappable

x = range(50)
scales = np.linspace(0, 2, 7)
locs = range(4)
cmap = plt.get_cmap("Spectral")
norm = plt.Normalize(scales.min(), scales.max())

fig, axes = plt.subplots(2,2, constrained_layout=True, sharey=True)

for s_plot, ax in enumerate(axes.flat):
for scale in scales:
y = np.random.normal(loc=locs[s_plot], scale=scale, size=50)
sc = ax.scatter(x, y, c=[cmap(norm(scale))], s=5)
ax.set_title("Mean = {:d}".format(locs[s_plot]))

sm = ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])
cbar = fig.colorbar(sm, ax=axes[:,1])
cbar.ax.set_title("scale")

plt.show()

Sample Image

Create different colorbars for combined scatter plot

Pandas plotting does a lot of things automatically, but isn't always easy to change afterwards. In this case, pandas doesn't take into account that twice the same ax is used, and calls plt.colorbar twice.

If manipulation of the result is desired, it is often easier to create the plot directly with matplotlib. Note that the second colorbar is drawn closest to the plot. Therefore, the order is changed in the code below.

import pandas as pd
import matplotlib.pyplot as plt

fig = plt.figure(num=1, clear=True)
ax = fig.add_subplot()

d = pd.DataFrame({'a': range(10), 'b': range(10), 'c': range(10)})
e = pd.DataFrame({'a': range(1,11), 'b': range(10), 'c': range(10)})

d_scatter = ax.scatter(x=d['a'], y=d['b'], c=d['c'], cmap='GnBu')
e_scatter = ax.scatter(x=e['a'], y=e['b'], c=e['c'], cmap='RdPu')
plt.colorbar(e_scatter)
plt.colorbar(d_scatter)

plt.show()

demo plot

PS: When there is more than one colorbar, the bars can also be put explicitly into their own subplot. That way the mutual distances can be controlled better. Especially when there would be 3 or more colorbars, things would look ugly otherwise.

import pandas as pd
import matplotlib.pyplot as plt

fig, axes = plt.subplots(ncols=3, gridspec_kw={'width_ratios': [15, 1, 1] })

d = pd.DataFrame({'a': range(10), 'b': range(10), 'c': range(10)})
e = pd.DataFrame({'a': range(1,11), 'b': range(10), 'c': range(10)})

d_scatter = axes[0].scatter(x=d['a'], y=d['b'], c=d['c'], cmap='GnBu')
e_scatter = axes[0].scatter(x=e['a'], y=e['b'], c=e['c'], cmap='RdPu')

plt.colorbar(d_scatter, cax=axes[1])
plt.colorbar(e_scatter, cax=axes[2])

plt.show()

One colorbar for multiple scatter plots

It requires a bit of extra work:

  • You have to get the minimum and maximum of the cs (the colorbar values)
  • You have to clim each scatter plot

First the minimum and maximum:

zs = np.concatenate([z1, z2, z3], axis=0)
min_, max_ = zs.min(), zs.max()

Then the scatter plots with clim:

plt.scatter(x1, y1, c=z1,cmap='viridis_r',marker='s')
plt.clim(min_, max_)
plt.scatter(x2, y2, c=z2,cmap='viridis_r',marker='o')
plt.clim(min_, max_)
plt.scatter(x3, y3, c=z3,cmap='viridis_r',marker='^')
plt.clim(min_, max_)
plt.colorbar().set_label('Wind speed',rotation=270)

For a very simple dataset:

x1, x2, x3 = [1,2,3], [2,3,4], [3,4,5]
y1 = y2 = y3 = [1, 2, 3]
z1, z2, z3 = [1,2,3], [4,5,6], [7,8,9]

Sample Image

(python) Adding a colorbar by the dates of points in a 3D scatter plot with matplotlib

Since you didn't provide the data, I had to randomly generate it.

from mpl_toolkits.mplot3d import axes3d
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import Normalize
import numpy as np

# generate random data and dates
longitude = np.random.uniform(0, 1, 100)
latitude = np.random.uniform(0, 1, 100)
depth = np.random.uniform(0, 1, 100)

dates = []
for i in range(1, 13):
for j in range(1, 25):
if j < 10: n = "0" + str(j)
else: n = j
if i < 10: m = "0" + str(i)
else: n = i
dates.append("2022-{}-{}".format(m, n))

fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(projection='3d')

colors = mdates.date2num(dates[:100])
ax.scatter(longitude, latitude, -depth, c=colors, cmap='magma')
norm = Normalize(vmin=colors.min(), vmax=colors.max())

# choose a proper number of ticks to be shown on the colorbar
N = 5
ticks = np.linspace(colors.min(), colors.max(), N)
# convert the tick back to date format
labels = [mdates.num2date(t).strftime("%Y-%m-%d") for t in ticks]
cb = fig.colorbar(
mpl.cm.ScalarMappable(norm=norm, cmap='magma'),
ticks=ticks,
ax=ax,
label="Date"
)
cb.ax.set_yticklabels(labels)
plt.show()

Sample Image

Matplotlib Colorbar different from scatter colors?

Try restructuring your scatter plot as:

cmap = mpl.cm.hot
for ...
sc = ax.scatter(df.bv[i], df.ron[i], marker='<', edgecolors='black',
alpha=0.8, s=100, c=df.fom[i], norm=norm, cmap=cmap)
....
fig.colorbar(sc) # without the norm and cmap and call outside the loop

Multiple scatter plots with two colorbars

Ok, so it seems like adding the following to the code:

fig.colorbar(images[0][0], ax=axes, fraction=.05)
fig.colorbar(images[0][1], ax=axes, fraction=.05)

I tried this yesterday and it wasn't working, I must have had something in my notebook memory.

And just for completeness, here is the complete code:

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 3))

images =[]
for i in range(3):
images.append([axes[i].scatter(np.random.random(10), np.random.random(10),
c = np.random.random(10), vmin=0, vmax=1, cmap="Purples_r"),

axes[i].scatter(np.random.random(10),np.random.random(10),
c = np.random.random(10), vmin=0, vmax=1, cmap="Oranges_r")])

fig.colorbar(images[0][0], ax=axes, fraction=.05)
fig.colorbar(images[0][1], ax=axes, fraction=.05)

plt.show()

and here is a visual of what I was looking for:

Sample Image



Related Topics



Leave a reply



Submit