如何在matplotlib中自定义拟合水平条形图?

时间:2018-10-01 16:07:09

标签: python matplotlib tkinter graphics

我一直在努力将我的matplotlib图形嵌入到tkinter GUI中。我本可以使用QTPython,它看上去确实很整洁,但是为时已晚。

这是我下面的代码,用于更新tkinter GUI中的图形(它是嵌入式的,没有外部窗口),我想调整图表的大小以正确放置。到目前为止,我已经尝试了以下方法:

1)紧密布局:fig_findin.tight_layout() 2)Yticks包装真实 3)我尝试过从0.1到0.6的不同条形宽度

我的主要问题是减小灰色背景框(网格线框或子图)的高度。这样可以使标题完全可见,并且看起来与其他图形一致。我还希望包裹y_axis标签,但在现有框架中仍然可见。

这是我的matplotlib图代码。

def animate_artifact_graph(i):
    #######################################
    ''' GRAPH START '''
    #######################################
    ## DATA
    x_cat = [x[1] for x in db.query_artifact()]
    x_cat = x_cat[:-2]


    y_count = {}
    for i in x_cat:
        y_count[i] = 0

    artifact_name,proj_name,mod_name = artifact_type_select.get() ,proj_select.get(),proj_mod_select.get()
    if(artifact_name == 'All'):
        artifact_name = db.query_artifact_name()
    else:
        artifact_name = [artifact_name]

    observations_fr_project = db.query_closed_findings_by_project(proj_name,mod_name,artifact_name)

    title = proj_name + " - " + mod_name

    for i in observations_fr_project:
        y_count[i[2]] = y_count[i[2]] + 1

    y_count = { k:v for k, v in y_count.items() if v > 0 and k != 'RTM'}

    x = list(y_count.keys())
    y = list(y_count.values())

    # ## SHOW

    # rects = ax.patches
    # labels = [ i for i in list(y_count.values())]

    # for rect, label in zip(rects, labels):
    #     if(rect.get_height() > 0):
    #         height = rect.get_height() - 1.50
    #         width = rect.get_width() /2 
    #         ax.text(rect.get_x() + width, rect.get_y()+height-0.26,label)
    # ax.set_ylabel("Observations", fontsize=12)
    # ax.set_xlabel("Artifact Type", fontsize=12)
    ax.clear()
    now = datetime.datetime.now()
    date_display = now.strftime('%A, %d %B %Y, %H:%M')
    ax.set_title (title + "\n" + "Total number of findings per deliverable type\n(as of " + date_display + ")", fontsize=8)

    def func(pct, allvals):
        absolute = int(pct/100.*np.sum(allvals))
        return "{:.1f}%\n{:d}".format(pct, absolute)


    wedges, texts, autotexts = ax.pie(y, autopct=lambda pct: func(pct, y),
                                      textprops=dict(color="w"))

    ax.legend(wedges, x,
              title="Artifact Types",
              loc="center left",
              bbox_to_anchor=(1, 0, 0.5, 1))
    fig_artif.tight_layout()
    ax.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.

    #######################################
    ''' GRAPH END '''
    #######################################

def animate_finding_graph(i):
    #######################################
    ''' GRAPH START '''
    #######################################

    ## DATA
    x_cat = [x[1] for x in db.query_finding()]
    y_count = {}

    for i in x_cat:
        y_count[i] = 0

    artifact_name,proj_name,mod_name = artifact_type_select.get() ,proj_select.get(),proj_mod_select.get()
    if(artifact_name == 'All'):
        artifact_name = db.query_artifact_name()
    else:
        artifact_name = [artifact_name]

    observations_fr_project = db.query_closed_findings_by_project(proj_name,mod_name,artifact_name)

    title = proj_name + " - " + mod_name

    for i in observations_fr_project:
        y_count[i[1]] = y_count[i[1]] + 1

    y_count = { k:v for k, v in y_count.items() if v > 0 and k != 'nan'}
    y_count = OrderedDict(sorted(y_count.items(), key=lambda kv: kv[1],reverse=True))

    if(len(list(y_count.keys())) >= 5):
        to_remove = list(y_count.keys())[5:]
        for x in to_remove:
            del y_count[x]

    x = list(y_count.values())
    y = list(y_count.keys())

    ## SHOW
    ay.clear()
    bar_width = 0.4
    ay.barh(y,x,bar_width,align='edge',color='yellow')
    ay.invert_yaxis()
    rects = ay.patches
    # print("rects",len(rects))
    labels = [ i for i in list(y_count.values())]
    # print("\n")

    for rect, label in zip(rects, labels):
        height = rect.get_height()/2
        width = rect.get_width() - 0.50
        ay.text(rect.get_x() + width, rect.get_y()+height,label,fontsize=8)

    ay.tick_params(
    axis='x',          # changes apply to the x-axis
    which='both',      # both major and minor ticks are affected
    bottom=False,      # ticks along the bottom edge are off
    top=False,         # ticks along the top edge are off
    labelbottom=False) # labels along the bottom edge are off

    ay.set_yticklabels(y,fontsize=6,wrap=True)

    for tick in ay.yaxis.get_major_ticks():
        tick.label1.set_verticalalignment('center')
    now = datetime.datetime.now()
    date_display = now.strftime('%A, %d %B %Y, %H:%M')
    ay.set_title (title + "\n" + "Top 5 Deliverables.", fontsize=6)

    #######################################
    ## ''' GRAPH END '''
    #######################################

def artifact_graph():
    canvas_artifact = FigureCanvasTkAgg(fig_artif, master=tab1_closed_observations)
    canvas_artifact.get_tk_widget().grid(row=7,column=0,padx=10,pady=5,columnspan=3)

    ani = animation.FuncAnimation(fig_artif, animate_artifact_graph,interval=500)
    canvas_artifact.draw()   

    def export_win():
        output_folder = "./Reports/" + proj_select.get() + " -- " + proj_mod_select.get()
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)
        fig_artif.savefig(output_folder + "/artifact.png")

    export_artifact_graph = Button(tab1_closed_observations, text='Export', command=export_win)
    export_artifact_graph.grid(row=6,column=0,padx=70,pady=20,sticky='we',columnspan=2)

def finding_category():
    canvas_finding = FigureCanvasTkAgg(fig_findin, master=tab1_closed_observations)
    canvas_finding.get_tk_widget().grid(row=7,column=5,padx=10,pady=5,columnspan=3)

    ani = animation.FuncAnimation(fig_findin, animate_finding_graph,interval=500)
    canvas_finding.draw() 

    def export_win():
        output_folder = "./Reports/"+ proj_select.get() + " -- " + proj_mod_select.get()
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)
        fig_findin.savefig(output_folder + "/finding.png")

    export_finding_graph = Button(tab1_closed_observations, text='Export', command=export_win)
    export_finding_graph.grid(row=6,column=5,padx=70,pady=20,sticky='we',columnspan=3)

这是我的图表的外观:

enter image description here

1 个答案:

答案 0 :(得分:0)

我想出了如何贴身的方法,但仍然无法使yticks显得整洁。

要抓住的是减小杆的宽度并隐藏所有其他y轴附件。添加Wrap =垂直和垂直对齐标签会使它看起来很漂亮。

    bar_width = 0.4
    ay.barh(y,x,bar_width,color='yellow')

    ay.tick_params(
            axis='x',          # changes apply to the x-axis
            which='both',      # both major and minor ticks are affected
            bottom=False,      # ticks along the bottom edge are off
            top=False,         # ticks along the top edge are off
            labelbottom=False
     ) 

    ay.set_yticklabels(y,fontsize=6,wrap=True)

    for tick in ay.yaxis.get_major_ticks():
        tick.label1.set_verticalalignment('center')

这是现在的样子:

enter image description here