matplotlibの三次元プロットの見栄えを良くする その1

seabornはmatplotlibの二次元プロットの見栄えを良くしてくれるが, 三次元となるとうまくいかない. これはseabornのせいというよりもむしろ, matplotlibでの二次元と三次元の扱いが全く別である上に, 三次元では相当にパラメータのハードコードが行われているせいようのようだ. matplotlib 1.5.1ではこの辺り良くなりつつあるのでseabornもそのうち対応するかもしれない.

とはいえ, 今見栄えを良くしたい. plotlyを使う手もあるがmatplotlibでそこそこがんばってみる.

from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.axis3d import Axis
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib import cm
import itertools

import seaborn as sns
color_palette = sns.color_palette()
# color_palette = [
#     (0.2980392156862745, 0.4470588235294118, 0.6901960784313725),
#     (0.3333333333333333, 0.6588235294117647, 0.40784313725490196),
#     (0.7686274509803922, 0.3058823529411765, 0.3215686274509804),
#     (0.5058823529411764, 0.4470588235294118, 0.6980392156862745),
#     (0.8, 0.7254901960784313, 0.4549019607843137),
#     (0.39215686274509803, 0.7098039215686275, 0.803921568627451)]

fig = plt.figure(figsize=(8, 8), dpi=80)
ax = plt.subplot(111, projection='3d')

ax.set_axis_bgcolor('white')  # background color

for axis in (ax.xaxis, ax.yaxis, ax.zaxis):
    # axis._axinfo.update({
    #     # 'label' : {'va': 'center', 'ha': 'center'},
    #     # 'tick' : {'inward_factor': 0.2, 'outward_factor': 0.1},
    #     # 'axisline': {'linewidth': 0.5, 'color': (0, 0, 0, 1)},
    #     'grid' : {'color': (1, 1, 1, 1),'linewidth': 1.0},
    #     })

    # the grid color and width
    axis._axinfo['grid']['color'] = (1, 1, 1, 1)
    axis._axinfo['grid']['linewidth'] = 1.0

    for tick in axis.get_major_ticks():
        tick.label.set_fontsize(16)  # ticks label font size. 12 as a default

# set label texts. 'labelpad' means the distance between axis and label
ax.set_xlabel('X', fontsize=24, labelpad=14)
ax.set_ylabel('Y', fontsize=24, labelpad=14)
ax.set_zlabel('Z', fontsize=24, labelpad=14)

for axis in (ax.w_xaxis, ax.w_yaxis, ax.w_zaxis):
    axis.line.set_color("white")  # a color of each axis
    axis.set_pane_color((0.848, 0.848, 0.848, 1.0))  # a color of each pane
    # axis.set_pane_color((0.9176470588235294, 0.9176470588235294, 0.9490196078431372, 1.0))  # much more like the seaborn style

# make all ticks lines invisible
for line in itertools.chain(ax.get_xticklines(), ax.get_yticklines(), ax.get_zticklines()):
    line.set_visible(False)

#XXX: START

x = np.arange(-3, 3, 0.25)
y = np.arange(-3, 3, 0.25)
X, Y = np.meshgrid(x, y)
Z = np.sin(X)+ np.cos(Y)

# ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.viridis, linewidth=0, antialiased=False)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=sns.cubehelix_palette(8, start=0.5, rot=-0.75, as_cmap=True), linewidth=0, antialiased=False)

#XXX: END

plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
plt.show()

カラーマップにseabornのものを指定しているが, matplotlib 1.5.1では標準でviridisが使えるのでそちらが良いだろう.

Python3とmatplollib 1.5.1で試した. matplotlibの1.4系列などでは動かないかも.