matplotlib:如何使用标记大小/颜色作为图中的额外维度?

时间:2015-09-24 15:01:36

标签: python datetime matplotlib

我正在绘制一个时间序列,其中x是一系列 datetime.datetime 对象,y是一系列双打。

我想将标记大小映射到第三个系列z(并且还可能将标记颜色映射到第四个系列w),这在大多数情况下可以通过以下方式完成:

scatter(x, y, s=z, c=w)

除了 scatter() 不允许x成为一系列datetime.datetime个对象。

plot(x, y, marker='o', linestyle='None')
另一方面,

使用xdatetime.datetime(带有正确的刻度标签),但只能为所有点设置markerize / color,即无法将它们映射到额外的系列

看到scatterplot每个可以做我需要的一半,有两种方法可以做到吗?

更新 @tcaswell 的问题之后,我意识到scatter在{KeyError深了default_units() 1}}在matplotlib/dates.py的行中:

x = x[0]

果然,我的xy都是从大熊猫DataFrame获取的系列,没有' 0'在索引中。然后我尝试了两件事(都觉得有点hacky):

首先,我尝试将DataFrame索引修改为0..len(x),这导致matplotlib/axes/_axes.py内的不同错误:

offsets  = np.dstack((x,y))

dstack与熊猫系列并不好玩。所以我尝试将xy转换为numpy.array:

scatter(numpy.array(x), numpy.array(y), s=numpy.array(z))

这几乎有效,除了散射似乎无法自动缩放x轴并将所有内容折叠成一条直线,因此我必须明确重置xlim才能看到该情节。

所有这一切都是说scatter可以完成这项工作,尽管有点卷积。我一直认为matplotlib可以接受任何类似数组的输入,但显然如果数据不是需要一些内部体操的简单数字则不完全正确。

UPDATE2 我还尝试按照 @user3666197 的建议(感谢btw的编辑提示)。如果我理解正确,我首先将x转换为一系列matplotlib风格的日子':

mx = mPlotDATEs.date2num(list(x))

然后允许我直接打电话:

scatter(mx, y, s=z)

然后正确地标记轴,我打电话:

gca().xaxis.set_major_formatter( DateFormatter('%Y-%m-%d %H:%M'))

(如果是交互模式,请调用show()更新轴标签)

它工作得非常好,并且对我来说是一个更合适的'做事的方式,所以我会接受这个作为最好的答案。

3 个答案:

答案 0 :(得分:3)

有两种方法可以做到吗?是

但是,让我们举例说明:

enter image description here enter image description here

步骤A :从datetimematplotlib惯例 - 兼容 float 日期/时间
第B步:添加 3D | 4D | 5D 功能(使用其他{color | size | alpha} - 信息的编码维度)

像往常一样, devil 会被隐藏起来。

matplotlib 日期 几乎 相等,但等于:

#  mPlotDATEs.date2num.__doc__
#                  
#     *d* is either a class `datetime` instance or a sequence of datetimes.
#
#     Return value is a floating point number (or sequence of floats)
#     which gives the number of days (fraction part represents hours,
#     minutes, seconds) since 0001-01-01 00:00:00 UTC, *plus* *one*.
#     The addition of one here is a historical artifact.  Also, note
#     that the Gregorian calendar is assumed; this is not universal
#     practice.  For details, see the module docstring.

因此,强烈建议重新使用他们自己的"工具:

from matplotlib import dates as mPlotDATEs   # helper functions num2date()
#                                            #              and date2num()
#                                            #              to convert to/from.

管理轴标签&格式化和scale(min / max)是一个单独的问题

尽管如此,matplotlib也为这部分带来了武器:

from matplotlib.dates   import  DateFormatter,    \
                                AutoDateLocator,   \
                                HourLocator,        \
                                MinuteLocator,       \
                                epoch2num
from matplotlib.ticker  import  ScalarFormatter, FuncFormatter

并且可以例如:

    aPlotAX.set_xlim( x_min, x_MAX )               # X-AXIS LIMITs ------------------------------------------------------------------------------- X-LIMITs

    #lt.gca().xaxis.set_major_locator(      matplotlib.ticker.FixedLocator(  secs ) )
    #lt.gca().xaxis.set_major_formatter(    matplotlib.ticker.FuncFormatter( lambda pos, _: time.strftime( "%d-%m-%Y %H:%M:%S", time.localtime( pos ) ) ) )

    aPlotAX.xaxis.set_major_locator(   AutoDateLocator() )

    aPlotAX.xaxis.set_major_formatter( DateFormatter( '%Y-%m-%d %H:%M' ) )  # ----------------------------------------------------------------------------------------- X-FORMAT

    #--------------------------------------------- # 90-deg x-tick-LABELs

    plt.setp( plt.gca().get_xticklabels(),  rotation            = 90,
                                            horizontalalignment = 'right'
                                            )

    #------------------------------------------------------------------

添加{ 3D | 4D | 5D }转码

想象一下这种方法,请查看此示例, 使用不同的工具将信息的附加维度编码到{color |中size | alpha}。而{size | alpha}与散点相关,color matplotlib中还有其他工具,其中包含一组着色,适用于各种特定领域或人眼视觉/感知的色阶。对色阶/标准化缩放器的一个很好的解释是 here

enter image description here
您可能已经注意到,此 4D 示例仍然具有常量alpha(在真5D维度可视化中未使用第5个DOF)

答案 1 :(得分:1)

您可以将x中的对象从datetime.datertime转换为int(通过自1970年代以来的秒数表示)

import time

x = [time.mktime(elem.timetuple()) for elem in x]

然后将其传递给scatter

scatter(x, y, s=z, c=w)

答案 2 :(得分:1)

你可能会尝试for循环。只要您没有太多数据可以绘制,这是一个相对不错的选择。下面我写一个小例子:

import numpy as np
import matplotlib.pyplot as plt

x = np.random.rand(100)
y = np.random.rand(100)

mass = np.linspace(1,10,100)

for i in xrange(len(x)):
    plt.plot(x[i],y[i],'ko', markersize=mass[i])
plt.show()

enter image description here

原则上你可以对颜色做同样的事情。