python + matplotlib:如何在极坐标图中的轴和刻度标签之间插入更多空格?

时间:2013-11-26 16:21:38

标签: python charts matplotlib

我正在尝试用matplotlib和python 2.7创建一个极坐标图,但我正在努力如何增加同一轴的X轴和刻度线标签之间的空间。正如你在图片上看到的那样,12点和6点的标签看起来很好,我希望所有其他标签都有相同的空间。

我试过

ax.xaxis.LABELPAD = 10

但它没有任何效果。

enter image description here

这是我的代码(抱歉这个烂摊子......):

import numpy as np
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.dates
from matplotlib.dates import YearLocator, MonthLocator, DateFormatter
import matplotlib.cm as cm
import matplotlib.ticker as tkr
import pdb
def plot_clock(data,filename,path,**kwargs): # (x,y,colors,lab_x,lab_y,xTicks,filename,legend,**kwargs):
    bins = [0,0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5,11.5,12,12.5,13.5,14.5,15.5,16.5,17.5,18.5,19.5,20.5,21.5,22.5,23.5,23.999999];
    data = np.array(data)/(60*60)
    DATA_ = np.histogram(data,bins)[0]
    def hour_formatAM(x, p):
        #pdb.set_trace()
        if x > 0:
            return str(format(x*6/np.pi, "01.0f") + ':00')
        else:
            return '12:00'

    def hour_formatPM(x, p):
        #pdb.set_trace()
        if x > 0:
            return str(format(x*6/np.pi+12, "01.0f") + ':00')
        else:
            return '24:00'

    '''font = {'family' : 'normal',
        'weight' : 'bold',
        'size'   : 12}
    mpl.rc('font', **font)'''

    mpl.rcParams.update({'font.size': 8})
    #sub plot AM
    theta = np.array(bins[1:13]) * np.pi / 6
    radii =  DATA_[1:13]
    radii[-1] += DATA_[0]
    width = 1 * np.pi / 6

    fig = plt.figure(figsize=(5.5,3),dpi=600)
    ax = fig.add_subplot(121, polar=True)
    bars = ax.bar(theta, radii, width=width, bottom=0)
    ax.set_theta_offset(np.pi/2)
    ax.set_theta_direction(-1)

    ax.xaxis.set_ticks(np.arange(0, np.pi*2, np.pi/6))
    ax.get_xaxis().set_major_formatter(tkr.FuncFormatter(hour_formatAM))
    ax.yaxis.set_ticks(np.arange(1,max(DATA_),1))
    for t, bar in zip(theta, bars):
        bar.set_facecolor(plt.cm.jet(t / 12.))
        bar.set_alpha(0.5)


    #sub plot PM
    theta = np.array(bins[14:26]) * np.pi / 6
    radii =  DATA_[14:26]
    radii[-1] += DATA_[13]
    width = 1 * np.pi / 6

    ax = fig.add_subplot(122, polar=True)
    bars = ax.bar(theta, radii, width=width, bottom=0)
    ax.set_theta_offset(np.pi/2)
    ax.set_theta_direction(-1)
    pdb.set_trace()
    ax.xaxis.set_ticks(np.arange(0, np.pi*2, np.pi/6))
    ax.get_xaxis().set_major_formatter(tkr.FuncFormatter(hour_formatPM))
    ax.yaxis.set_ticks(np.arange(1,max(DATA_),1))
    for t, bar in zip(theta, bars):
        bar.set_facecolor(plt.cm.jet(t / 12.))
        bar.set_alpha(0.5) 
    #pdb.set_trace()
    #fig.tight_layout() 
    #xlabels = [item.get_text() for item in ax.get_xticklabels()]
    ax.xaxis.LABELPAD = 10 
    #[item.set_fontsize(12) for item in ax.xaxis.get_major_ticks()]

    fig.subplots_adjust(wspace = 0.4) # http://matplotlib.org/faq/howto_faq.html
    fig.savefig(path + filename,format='pdf')  


data = [ 10.49531611,  22.49511583,  10.90891806,  18.99525417,
        21.57165972,   6.687755  ,   6.52137028,  15.86534639,
        18.53823556,   6.32563583,  12.99365833,  11.06817056,
        17.29261306,  15.31288556,  19.16236667,  10.38483333,
        14.51442222,  17.01413611,   6.96102278,  15.98508611,
        16.5287    ,  15.26533889,  20.83520278,  17.21952056,
         7.3225775 ,  16.42534361,  14.38649722,  21.63573111,  16.19249444]
data = np.array(data)*60*60
plot_clock(data,'figure2_StartTime.pdf','./')

1 个答案:

答案 0 :(得分:9)

@dabillox已经提到使用frac kwarg到ax.set_thetagrids

然而,正如您所注意到的,您真正想要改变的是勾选标签的对齐方式,而不是刻度标签的整体径向位移。

另一方面,labelpad无效的原因是它控制轴标签之间的填充(例如plt.xlabelplt.ylabel)和轴,而不是刻度标签。

首先,您可以更清楚地编写示例代码。这或多或少是我接近你正在做的事情(请注意,这仍然会与刻度标签定位有相同的问题):

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tkr

def main():
    data = [ 10.49531611,  22.49511583,  10.90891806,  18.99525417,
            21.57165972,   6.687755  ,   6.52137028,  15.86534639,
            18.53823556,   6.32563583,  12.99365833,  11.06817056,
            17.29261306,  15.31288556,  19.16236667,  10.38483333,
            14.51442222,  17.01413611,   6.96102278,  15.98508611,
            16.5287    ,  15.26533889,  20.83520278,  17.21952056,
             7.3225775 ,  16.42534361,  14.38649722,  21.63573111,  16.19249444]
    data = np.array(data)*60*60
    plot_clock(data)
    plt.show()

def plot_clock(data):
    def hour_formatAM(x, p):
        hour = x * 6 / np.pi
        return '{:0.0f}:00'.format(hour) if x > 0 else '12:00'

    def hour_formatPM(x, p):
        hour = x * 6 / np.pi
        return '{:0.0f}:00'.format(hour + 12) if x > 0 else '24:00'

    def plot(ax, theta, counts, formatter):
        colors = plt.cm.jet(theta / 12.0)
        ax.bar(theta, counts, width=np.pi/6, color=colors, alpha=0.5)
        ax.xaxis.set_major_formatter(tkr.FuncFormatter(formatter))

    plt.rcParams['font.size'] = 8

    bins = np.r_[0, 0.5:12, 12, 12.5:24,  23.99999]
    data = np.array(data) / (60*60)
    counts = np.histogram(data,bins)[0]

    counts[13] += counts[0]
    counts[-1] += counts[13]

    fig, axes = plt.subplots(ncols=2, figsize=(5.5, 3), dpi=200,
                             subplot_kw=dict(projection='polar'))
    fig.subplots_adjust(wspace=0.4)
    for ax in axes:
        ax.set(theta_offset=np.pi/2, theta_direction=-1,
               xticks=np.arange(0, np.pi*2, np.pi/6),
               yticks=np.arange(1, counts.max()))

    plot(axes[0], bins[1:13] * np.pi / 6, counts[1:13], hour_formatAM)
    plot(axes[1], bins[14:26] * np.pi / 6, counts[14:26], hour_formatPM)

main()

enter image description here


如果我们想避免错误对齐的刻度标签,我们可以根据位置设置水平对齐:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tkr

def main():
    data = [ 10.49531611,  22.49511583,  10.90891806,  18.99525417,
            21.57165972,   6.687755  ,   6.52137028,  15.86534639,
            18.53823556,   6.32563583,  12.99365833,  11.06817056,
            17.29261306,  15.31288556,  19.16236667,  10.38483333,
            14.51442222,  17.01413611,   6.96102278,  15.98508611,
            16.5287    ,  15.26533889,  20.83520278,  17.21952056,
             7.3225775 ,  16.42534361,  14.38649722,  21.63573111,  16.19249444]
    data = np.array(data)*60*60
    axes = plot_clock(data)
    for ax in axes:
        realign_polar_xticks(ax)
    plt.show()

def realign_polar_xticks(ax):
    for x, label in zip(ax.get_xticks(), ax.get_xticklabels()):
        if np.sin(x) > 0.1:
            label.set_horizontalalignment('left')
        if np.sin(x) < -0.1:
            label.set_horizontalalignment('right')

def plot_clock(data):
    def hour_formatAM(x, p):
        hour = x * 6 / np.pi
        return '{:0.0f}:00'.format(hour) if x > 0 else '12:00'

    def hour_formatPM(x, p):
        hour = x * 6 / np.pi
        return '{:0.0f}:00'.format(hour + 12) if x > 0 else '24:00'

    def plot(ax, theta, counts, formatter):
        colors = plt.cm.jet(theta / 12.0)
        ax.bar(theta, counts, width=np.pi/6, color=colors, alpha=0.5)
        ax.xaxis.set_major_formatter(tkr.FuncFormatter(formatter))

    plt.rcParams['font.size'] = 8

    bins = np.r_[0, 0.5:12, 12, 12.5:24,  23.99999]
    data = np.array(data) / (60*60)
    counts = np.histogram(data,bins)[0]

    counts[13] += counts[0]
    counts[-1] += counts[13]

    fig, axes = plt.subplots(ncols=2, figsize=(5.5, 3), dpi=200,
                             subplot_kw=dict(projection='polar'))
    fig.subplots_adjust(wspace=0.5)

    for ax in axes:
        ax.set(theta_offset=np.pi/2, theta_direction=-1,
               xticks=np.arange(0, np.pi*2, np.pi/6),
               yticks=np.arange(1, counts.max()))

    plot(axes[0], bins[1:13] * np.pi / 6, counts[1:13], hour_formatAM)
    plot(axes[1], bins[14:26] * np.pi / 6, counts[14:26], hour_formatPM)
    return axes

main()

enter image description here

最后,如果你想“正确”地做到这一点,无论θ方向和偏移如何,都要做类似的事情:

def realign_polar_xticks(ax):
    for theta, label in zip(ax.get_xticks(), ax.get_xticklabels()):
        theta = theta * ax.get_theta_direction() + ax.get_theta_offset()
        theta = np.pi/2 - theta
        y, x = np.cos(theta), np.sin(theta)
        if x >= 0.1:
            label.set_horizontalalignment('left')
        if x <= -0.1:
            label.set_horizontalalignment('right')
        if y >= 0.5:
            label.set_verticalalignment('bottom')
        if y <= -0.5:
            label.set_verticalalignment('top')

enter image description here