Как раскрасить определенную линию сетки/линию в 3D-графике рассеяния Matplotlib?

Я пытаюсь изменить цвет/толщину определенной линии сетки в 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)}})

Заранее спасибо за помощь.


person tylerswright    schedule 28.07.2015    source источник


Ответы (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 является кортеж (местоположение, цвет). Вы также можете использовать список кортежей с оператором *.

3D-график с цветными линиями сетки

Ta-da!

------- Старый ответ ------- Ваша первая попытка выглядит хорошо, за исключением того, что я думаю, вы хотите просто построить линию от (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)

3D-график

Это определенно взломано, и вы можете немного поиграть с координатами, чтобы посмотреть, сможете ли вы заставить их лучше соответствовать. Но, думаю, в крайнем случае сойдет. Я посмотрю, смогу ли я найти лучший способ.

person Amy Teegarden    schedule 28.07.2015
comment
Да, это выглядит хорошо, как я сам убедился, но как только вы начинаете поворачивать фигуру, это перестает быть полезным, так как это линия, а не ось. Любые предложения по фактическому окрашиванию или утолщению линии сетки, а не построению новой? - person tylerswright; 28.07.2015
comment
Я добавил это: plt.plot([x_min, x_min], [y_min, y_max], [-30, -30], 'k-', lw = 2) - person mauve; 28.07.2015
comment
Мне это понравилось больше, когда я изменил lw на 0,5. Все еще видно, выглядит более естественно. - person mauve; 28.07.2015
comment
Не могли бы вы добавить изображение вашей фигуры для визуального представления? - person tylerswright; 28.07.2015
comment
@tylerswright, хорошая новость в том, что я понял, как изменить цвет линии сетки! Плохая новость заключается в том, что он сбрасывается, когда я вызываю plt.show() или plt.savefig(), что выглядит жестко запрограммированным. Выполнение того, что вы хотите, вероятно, потребует возиться с исходным кодом matplotlib. Код, который вам нужен, находится в mpl_toolkits/mplot3d/axis_3d.py. Ищите draw_grid. - person Amy Teegarden; 28.07.2015
comment
Я нашел немного кода в разделе ''' if self.axes._draw_grid: ''', но не уверен, как это было реализовано. Думаете, вы можете выложить исправленную версию своего кода? @Эми Тигарден - person tylerswright; 29.07.2015
comment
@tylerswright Да, проблема с self.axes._draw_grid заключается в том, что он устанавливает цвет всех линий в цвет в axinfo. Сначала я попытался изменить код, чтобы сделать это только в том случае, если количество цветов не совпадает с количеством линий, но затем черная линия исчезает, если вы увеличиваете масштаб (таким образом изменяя количество линий сетки). Я думаю, что необходимо хранить некоторые вещи в качестве атрибутов. Я собираюсь посмотреть, смогу ли я найти способ сделать это, а также избежать путаницы с исходным кодом, создав вместо этого собственный класс оси. У тебя крайний срок? - person Amy Teegarden; 29.07.2015
comment
Сроков нет, но очевидно, что чем раньше, тем лучше. Спасибо за вашу помощь, и я буду продолжать исследования, а также. @Эми Тигарден - person tylerswright; 29.07.2015
comment
@tylerswright, я не знаю, уведомляет ли он вас, когда я редактирую ответ, но у меня есть ваше решение. Не требуется изменение кода в исходной папке matplotlib. :) - person Amy Teegarden; 30.07.2015
comment
Потрясающий!!! Это отличное решение, и оно отлично работает. Сегодня утром я немного покопаюсь в этом, чтобы убедиться, что я следую внесенным вами изменениям. Я прокомментирую любые дополнительные вопросы, которые у меня есть, и еще раз спасибо за помощь. @Эми Тигарден - person tylerswright; 30.07.2015