9

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

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沿绘图右边缘的垂直颜色条(代表 中的颜色图)?

注意:我发现 Matplotlib完全难以理解,这既适用于它的设计,也适用于它的文档。(不是因为缺乏尝试:我投入了大量的时间、精力,甚至是一些钱。)所以我会很感激完整的、有效的代码(即使它只是一个玩具示例),因为我很可能会赢无法填写省略的细节或修复代码中的错误。


编辑:我修复了上面“代码草图”中的一个重要遗漏,即每次调用ax.scatter. 这就是使用多次调用来创建散点图的原因ax.scatter,尽管不可否认,至少可以将调用 scatter 的次数减少到每个使用的 maker 形状一个;例如

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到一个,但这个要求似乎与我对同一散点图中多个标记形状的绝对要求相冲突。

4

4 回答 4

12

如果您必须为每组使用不同的标记,则必须做一些额外的工作并强制所有标记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)

一旦将数据全部打入一维数组,制作散点图并保留返回值:

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

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

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

您需要这样做,以便颜色条知道要使用哪个颜色图(地图和范围)。

在此处输入图像描述

于 2012-12-19T05:21:57.727 回答
7

我认为您最好的选择是将您的数据填充到熊猫数据框中,并像这样循环遍历所有标记:

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')

结果图

于 2012-12-21T01:59:50.330 回答
1

我认为这应该可以解决问题。我很确定我不久前从一个 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')
于 2012-12-19T02:44:04.620 回答
1

The answer to this can be to only plot a single scatter, which would then directly allow for a colobar to be created. This involves putting the markers into the PathCollection created by the scatter a posteriori, but it can be easily placed in a function. This function comes from my answer on another question, but is directly applicable here.

Taking the data from @PaulH's post this would look like

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()

enter image description here

于 2018-11-09T14:57:01.390 回答