matplotlib 如何向这样创建的散点图添加颜色条?

jgwigjjp  于 2023-03-03  发布在  其他
关注(0)|答案(5)|浏览(273)

我用代码创建散点图,本质上,是这样的

cmap = (matplotlib.color.LinearSegmentedColormap.
        from_list('blueWhiteRed', ['blue', 'white', 'red']))

fig = matplotlib.figure.Figure(figsize=(4, 4), dpi=72)
ax = fig.gca()

for record in data:
    level = record.level # a float in [0.0, 1.0]
    marker = record.marker # one of 'o', 's', '^', '*', etc.
    ax.scatter(record.x, record.y, marker=marker,
               c=level, vmin=0, vmax=1, cmap=cmap, **otherkwargs)

# various settings of ticks, labels, etc. omitted

canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig)
fig.set_canvas(canvas)
canvas.print_png('/path/to/output/fig.png')

我的问题是:
我需要在上面的代码中添加什么才能在图的右边缘得到一个垂直的颜色条(用cmap表示颜色Map表)?

    • 注意**:我发现Matplotlib***完全不可理解***,这既适用于它的设计,也适用于它的文档。(不是因为缺乏尝试:我已经投入了大量的时间、精力,甚至一些金钱。)所以我希望有完整的、工作正常的代码(即使它只是一个玩具示例),因为很可能我无法填充省略的细节或修复代码中的bug。

编辑:我修正了上面的"代码草图"中的一个重要遗漏,即每次调用ax.scatter时指定特定于记录的标记,这就是创建多次调用ax.scatter的散点图的原因,尽管不可否认,至少可以将调用次数减少到每个标记形状使用一次;例如:

for marker in set(record.marker for record in data):
    X, Y, COLOR = zip(*((record.x, record.y, record.level)
                        for record in data if record.marker == marker))
    ax.scatter(X, Y, marker=marker,
               c=COLOR, vmin=0, vmax=1, cmap=cmap,
               **otherkwargs)

我尝试扩展相同的技巧,将对ax.scatter的所有调用合并为一个调用(通过传递一个标记序列作为marker参数),如下所示:

X, Y, COLOR, MARKER = zip(*((record.x, record.y, record.level, record.marker)
                            for record in data))

ax.scatter(X, Y, marker=MARKER,
           c=COLOR, vmin=0, vmax=1, cmap=cmap,
           **otherkwargs)

...但这失败了。错误如下所示(修剪一些长路径后):

Traceback (most recent call last):
  File "src/demo.py", line 222, in <module>
    main()
  File "src/demo.py", line 91, in main
    **otherkwargs)
  File "<abbreviated-path>/matplotlib/axes.py", line 6100, in scatter
    marker_obj = mmarkers.MarkerStyle(marker)
  File "<abbreviated-path>/matplotlib/markers.py", line 113, in __init__
    self.set_marker(marker)
  File "<abbreviated-path>/matplotlib/markers.py", line 179, in set_marker
    raise ValueError('Unrecognized marker style {}'.format(marker))
ValueError: Unrecognized marker style ('^', 'o', '^', '*', 'o', 's', 'o', 'o', '^', 's', 'o', 'o', '^', '^', '*', 'o', '*', '*', 's', 's', 'o', 's', 'o', '^', 'o', 'o', '*', '^', 's', '^', '^', 's', '*')

AFAICT,tcaswell的配方 * 要求 * 将对ax.scatter的调用减少到单个调用,但此要求似乎与我对同一散点图中多个标记形状的绝对要求相冲突。

qojgxg4l

qojgxg4l1#

如果您必须为每个集合使用不同的标记,则必须做一些额外的工作,并强制所有clims相同(否则它们默认从每个散点图的c数据的最小值/最大值缩放)。

from pylab import *
import matplotlib.lines as mlines
import itertools
fig = gcf()
ax = fig.gca()

# make some temorary arrays
X = []
Y = []
C = []
cb = None
# generate fake data
markers = ['','o','*','^','v']
cmin = 0
cmax = 1
for record,marker in itertools.izip(range(5),itertools.cycle(mlines.Line2D.filled_markers)):
    x = rand(50)
    y = rand(50)
    c = rand(1)[0] * np.ones(x.shape)
    if cb is None:
        s = ax.scatter(x,y,c=c,marker=markers[record],linewidths=0)
        s.set_clim([cmin,cmax])
        cb = fig.colorbar(s)
    else:
        s = ax.scatter(x,y,c=c,marker=markers[record],linewidths=0)
        s.set_clim([cmin,cmax])

cb.set_label('Cbar Label Here')

linewidths=0设置了形状边框的宽度,我发现对于小形状来说,黑色边框会压倒填充的颜色。

如果你只需要一个形状,你可以用一个散点图来完成这一切,没有必要为每一次通过你的循环做一个单独的形状。

from pylab import *
fig = gcf()
ax = fig.gca()

# make some temorary arrays
X = []
Y = []
C = []
# generate fake data
for record in range(5):
    x = rand(50)
    y = rand(50)
    c = rand(1)[0] * np.ones(x.shape)
    print c
    X.append(x)
    Y.append(y)
    C.append(c)

X = np.hstack(X)
Y = np.hstack(Y)
C = np.hstack(C)

一旦你把所有的数据都打到一个1D数组中,做散点图,并保留返回值:

s = ax.scatter(X,Y,c=C)

然后创建颜色条,并将scatter返回的对象作为第一个参数传递。

cb = plt.colorbar(s)
cb.set_label('Cbar Label Here')

您需要执行此操作,以便颜色栏知道要使用哪个颜色贴图(贴图和范围)。

zu0ti5jz

zu0ti5jz2#

我认为你最好的选择是把你的数据填充到一个Pandas数据框中,然后像这样循环遍历你所有的标记:

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

markers = ['s', 'o', '^']
records = []
for n in range(37):
    records.append([np.random.normal(), np.random.normal(), np.random.normal(), 
                    markers[np.random.randint(0, high=3)]])

records = pd.DataFrame(records, columns=['x', 'y', 'z', 'marker'])

fig, ax = plt.subplots()
for m in np.unique(records.marker):
    selector = records.marker == m
    s = ax.scatter(records[selector].x, records[selector].y, c=records[selector].z,
                   marker=m, cmap=plt.cm.coolwarm, 
                   vmin=records.z.min(), vmax=records.z.max())

cbar = plt.colorbar(mappable=s, ax=ax)
cbar.set_label('My Label')

v64noz0r

v64noz0r3#

我想这应该可以了,我很确定我是从一个matplotlib的烹饪书例子中找到的,但是我现在好像找不到了...

from mpl_toolkits.axes_grid1 import make_axes_locatable

cmap = (matplotlib.color.LinearSegmentedColormap.
        from_list('blueWhiteRed', ['blue', 'white', 'red']))

fig = matplotlib.figure.Figure(figsize=(4, 4), dpi=72)
ax = fig.gca()

for record in data:
    level = record.level # a float in [0.0, 1.0]
    ax.scatter(record.x, record.y,
               c=level, vmin=0, vmax=1, cmap=cmap, **otherkwargs)

# various settings of ticks, labels, etc. omitted

divider= make_axes_locatable(ax)
cax = divider.append_axes("right", size="1%", pad=0.05)
cb = plt.colorbar(cax=cax)
cb.set_label('Cbar Label Here')

canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig)
fig.set_canvas(canvas)
canvas.print_png('/path/to/output/fig.png')
2exbekwf

2exbekwf4#

这个问题的答案 * 可以 * 是只绘制一个散点,这样就可以直接创建一个colobar。这涉及到将标记放入由散点后验创建的PathCollection中,但它可以很容易地放入一个函数中。这个函数来自另一个问题的my answer,但在这里直接适用。
从@PaulH的post获取数据,如下所示

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

def mscatter(x,y,ax=None, m=None, **kw):
    import matplotlib.markers as mmarkers
    ax = ax or plt.gca()
    sc = ax.scatter(x,y,**kw)
    if (m is not None) and (len(m)==len(x)):
        paths = []
        for marker in m:
            if isinstance(marker, mmarkers.MarkerStyle):
                marker_obj = marker
            else:
                marker_obj = mmarkers.MarkerStyle(marker)
            path = marker_obj.get_path().transformed(
                        marker_obj.get_transform())
            paths.append(path)
        sc.set_paths(paths)
    return sc

markers = ['s', 'o', '^']
records = []
for n in range(37):
    records.append([np.random.normal(), np.random.normal(), np.random.normal(), 
                    markers[np.random.randint(0, high=3)]])

records = pd.DataFrame(records, columns=['x', 'y', 'z', 'marker'])

fig, ax = plt.subplots()
sc = mscatter(records.x, records.y, c=records.z, m=records.marker, ax=ax)
fig.colorbar(sc, ax=ax)

plt.show()

tcomlyy6

tcomlyy65#

这也可能是一个非常简单的解决方案。

fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8,8)) 

p = ax.scatter(x, y, c=y, cmap='cmo.deep')
fig.colorbar(p,ax=ax,orientation='vertical',label='labelname')

相关问题