【问题标题】:How to color a specific gridline/tickline in 3D Matplotlib Scatter Plot figure?如何在 3D Matplotlib 散点图中为特定的网格线/刻度线着色?
【发布时间】:2015-07-28 18:32:56
【问题描述】:

我正在尝试修改 3D matplotlib 散点图中特定网格线的颜色/粗细,在这种情况下,我希望 -30 z 轴网格线为黑色、粗体或加粗,以便在其他网格线中脱颖而出网格线。 这是从 mplot3d 散点图教程中看到的基本代码:

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

def randrange(n, vmin, vmax):
    return (vmax-vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
n = 100
for c, m, zl, zh in [('r', 'o', -50, -25), ('b', '^', -30, -5)]:
    xs = randrange(n, 23, 32)
    ys = randrange(n, 0, 100)
    zs = randrange(n, zl, zh)
    scat = ax.scatter(xs, ys, zs, c=c, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

我尝试了以下方法:

y_min, y_max = scat.axes.get_ylim()
scat.axes.set_ylim([y_min,y_max])
x_min, x_max = scat.axes.get_xlim()
scat.axes.set_xlim([x_min,x_max])

plt.plot([0.0,0.0], [y_min,y_max], 'k-', lw=2)
plt.plot([x_min,x_max], [0.0225,0.0225], 'k-', lw=2)

ax.w_zaxis._axinfo.update({ztick[2] : {'color': (0, 0, 0, 1)}})

提前感谢您的帮助。

【问题讨论】:

    标签: python matplotlib scatter mplot3d


    【解决方案1】:

    这是使网格线颜色可变所需的代码:

    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D
    from mpl_toolkits.mplot3d.axis3d import Axis
    import matplotlib.pyplot as plt
    import matplotlib.projections as proj
    from matplotlib.colors import colorConverter
    
    
    class axis3d_custom(Axis):
        def __init__(self, adir, v_intervalx, d_intervalx, axes, *args, **kwargs):
            Axis.__init__(self, adir, v_intervalx, d_intervalx, axes, *args, **kwargs)
            self.gridline_colors = []
        def set_gridline_color(self, *gridline_info):
            '''Gridline_info is a tuple containing the value of the gridline to change
            and the color to change it to. A list of tuples may be used with the * operator.'''
            self.gridline_colors.extend(gridline_info)
        def draw(self, renderer):
            # filter locations here so that no extra grid lines are drawn
            Axis.draw(self, renderer)
            which_gridlines = []
            if self.gridline_colors:
                locmin, locmax = self.get_view_interval()
                if locmin > locmax:
                    locmin, locmax = locmax, locmin
    
                # Rudimentary clipping
                majorLocs = [loc for loc in self.major.locator() if
                             locmin <= loc <= locmax]
                for i, val in enumerate(majorLocs):
                    for colored_val, color in self.gridline_colors:
                        if val == colored_val:
                            which_gridlines.append((i, color))
                colors = self.gridlines.get_colors()
                for val, color in which_gridlines:
                    colors[val] = colorConverter.to_rgba(color)
                self.gridlines.set_color(colors)
                self.gridlines.draw(renderer, project=True)
    
    class XAxis(axis3d_custom):
        def get_data_interval(self):
            'return the Interval instance for this axis data limits'
            return self.axes.xy_dataLim.intervalx
    
    class YAxis(axis3d_custom):
        def get_data_interval(self):
            'return the Interval instance for this axis data limits'
            return self.axes.xy_dataLim.intervaly
    
    class ZAxis(axis3d_custom):
        def get_data_interval(self):
            'return the Interval instance for this axis data limits'
            return self.axes.zz_dataLim.intervalx
    
    class Axes3D_custom(Axes3D):
        """
        3D axes object.
        """
        name = '3d_custom'
    
        def _init_axis(self):
            '''Init 3D axes; overrides creation of regular X/Y axes'''
            self.w_xaxis = XAxis('x', self.xy_viewLim.intervalx,
                                self.xy_dataLim.intervalx, self)
            self.xaxis = self.w_xaxis
            self.w_yaxis = YAxis('y', self.xy_viewLim.intervaly,
                                self.xy_dataLim.intervaly, self)
            self.yaxis = self.w_yaxis
            self.w_zaxis = ZAxis('z', self.zz_viewLim.intervalx,
                                self.zz_dataLim.intervalx, self)
            self.zaxis = self.w_zaxis
    
            for ax in self.xaxis, self.yaxis, self.zaxis:
                ax.init3d()
    proj.projection_registry.register(Axes3D_custom)
    

    只需复制并粘贴并放在文件顶部即可。设置图形时,您需要使用新名称作为投影:ax = fig.add_subplot(111, projection='3d_custom'),然后您可以执行以下操作来更改网格线的颜色。

    color = ((-30, 'red'), (-40, (0, 0, 0, 1)))
    ax.zaxis.set_gridline_color(*color)
    ax.xaxis.set_gridline_color((24, 'blue'))
    

    set_gridline_color 的参数是一个元组(位置、颜色)。您还可以使用带有 * 运算符的元组列表。

    哒哒!

    --------旧答案----- 您的第一次尝试看起来不错,但我认为您只想绘制一条从 (x_min, y_max, -30) 到 (x_max, y_max, -30) 的线。

    y_min, y_max = ax.get_ylim()
    ax.set_ylim([y_min,y_max])
    x_min, x_max = ax.get_xlim()
    ax.set_xlim([x_min,x_max])
    
    plt.plot([x_min,x_max], [y_max,y_max], [-30, -30], 'k-', lw=2)
    

    这绝对是 hacky,您可能想稍微调整一下坐标,看看是否可以让它更适合。但我猜它会在紧要关头完成。我看看能不能找到更好的办法。

    【讨论】:

    • 是的,我自己发现这看起来不错,但是一旦你开始转动图形,它就不再有用了,因为它是一条线而不是轴。对于实际着色或加粗网格线而不是完全绘制新网格线有什么建议吗?
    • 我添加了这个:plt.plot([x_min, x_min], [y_min, y_max], [-30, -30], 'k-', lw = 2)
    • 当我将 lw 更改为 0.5 时,我更喜欢这个。仍然可见,看起来更自然。
    • 能否请您添加您的人物图像以进行视觉展示?
    • @tylerswright,好消息是我知道如何改变网格线的颜色!坏消息是,当我调用 plt.show() 或 plt.savefig() 时,它会以一种看起来是硬编码的方式重置。做你想做的事可能需要弄乱matplotlib的源代码。您想要的代码在 mpl_toolkits/mplot3d/axis_3d.py 中。寻找 draw_grid。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    • 2022-07-08
    • 2016-12-22
    • 1970-01-01
    • 2019-05-08
    • 2017-10-23
    相关资源
    最近更新 更多