matplotlib将df绘制到矩形

时间:2020-10-20 17:23:13

标签: python pandas dataframe matplotlib plot

我想通过python中的matplotlib创建一个“ ractangle-plot”。不幸的是我没有图像样本,所以我必须以最好的方式描述我的问题。

输入是具有不同时间增量和数字的df:

df = pd.DataFrame({'timedelta':[75,80,55,20,45],
               'numb1':[8,25,11,14,8],
               'timedelta1': [55,60,45,15,30],
               'numb2':[10,30,15,18,10],
               'timedelta2': [45,50,35,10,20]})

df['timedelta'] = pd.to_timedelta(df['timedelta'], unit='T')
df['timedelta1'] = pd.to_timedelta(df['timedelta1'], unit='T')
df['timedelta2'] = pd.to_timedelta(df['timedelta2'], unit='T')

输出:

   timedelta    numb1   timedelta1  numb2   timedelta2
0   01:15:00        8     00:55:00     10     00:45:00
1   01:20:00       25     01:00:00     30     00:50:00
2   00:55:00       11     00:45:00     15     00:35:00
3   00:20:00       14     00:15:00     18     00:10:00
4   00:45:00        8     00:30:00     10     00:20:00

现在,我想可视化此df。我想有一个矩形,其麻木向上,而timedelta朝右-每行都有一个新图。

例如row = 0:

rectangle (overall):
width  = timedelta (=01:15:00)
hight = numb2 (=10) 

在此矩形内-两个不同颜色的较小矩形(所有矩形应从左下角的同一点开始)

width1 = timedelta1
hight1 = numb1

width2 = timedelta2
hight2 = numb2

我还需要为轴(高度和宽度)和矩形添加标签。

编辑

使用以下代码,我设法创建了所需的矩形。

如何根据各个矩形(最好使用大括号)标记轴。我不需要这里的值,但需要使用的列的名称。

for row in df.index:
    fig = plt.figure()
    ax = fig.add_axes([0,0,1,1])
    
    p = patches.Rectangle((0,0), 1, 1, color= 'grey', alpha=0.2)
    
    x1 = df['timedelta1'][row]/df['timedelta'][row]
    y1 = df['numb1'][row]/df['numb2'][row]
    p1 = patches.Rectangle((0,0), x1, y1, color= 'grey', alpha=0.8)
    
    x2 = df['timedelta2'][row]/df['timedelta'][row]
    y2 = df['numb2'][row]/df['numb2'][row]
    p2 = patches.Rectangle((0,0), x2, y2, color= 'grey', alpha=0.5)
    
    ax.add_patch(p)
    ax.add_patch(p1)
    ax.add_patch(p2)
    
    ax.set_axis_off()
    plt.show()

这是我以前的情节,现在我想用相应的列名(= timedelta/1/2numb1/2(最好用大括号)标记每个矩形的宽度和高度

enter image description here

2 个答案:

答案 0 :(得分:1)

这是我的答案:

我唯一还没有做的就是以表格形式排列子图-例如fig, axes = plt.subplots(x,y) ...

df = pd.DataFrame({'timedelta':[75,80,55,20,45],
                   'numb1':[8,25,11,14,8],
                   'timedelta1': [55,60,45,15,30],
                   'numb2':[10,30,15,18,10],
                   'timedelta2': [45,50,35,10,20]})
n = len(df.index)

fig, axes = plt.subplots(n , figsize=(5,20))
for i, ax in enumerate(axes):    
    p = patches.Rectangle((0,0), 1, 1, color= 'grey', alpha=0.2)

    x1 = df['timedelta1'][i]/df['timedelta'][i]
    y1 = df['numb1'][i]/df['numb2'][i]
    p1 = patches.Rectangle((0,0), x1, y1, color= 'grey', alpha=0.8)

    x2 = df['timedelta2'][i]/df['timedelta'][i]
    y2 = df['numb2'][i]/df['numb2'][i]
    p2 = patches.Rectangle((0,0), x2, y2, color= 'grey', alpha=0.5)

    ax.add_patch(p)
    ax.add_patch(p1)
    ax.add_patch(p2)
    
    #td
    pe_a = [0.0, -0.2]
    pe_b = [1, -0.2]
    
    
    #td1
    pe_1a = [0.0, -0.1]
    pe_1b = [x1, -0.1]

    #td2
    pe_2a = [0.0, 0.0]
    pe_2b = [x2, 0.0]

    # fontdict for curly bracket 1 text
    font = {'family': 'serif',
            'color':  'k',
            'weight': 'bold',
            'style': 'italic',
            'size': 10,
            }

    # coefficient for curly
    k_r1 = 0.02
    
    # td - Brace
    curlyBrace.curlyBrace(fig, ax, pe_b, pe_a, k_r1, bool_auto=True, str_text='td', color='black', lw=1, int_line_num=1, fontdict=font)
    curlyBrace.curlyBrace(fig, ax, pe_1b, pe_1a, k_r1, bool_auto=True, str_text='td1', color='black', lw=1, int_line_num=1, fontdict=font)
    curlyBrace.curlyBrace(fig, ax, pe_2b, pe_2a, k_r1, bool_auto=True, str_text='td2', color='black', lw=1, int_line_num=1, fontdict=font)
    
    # numb1
    h_1a = [0.0, y1]
    h_1b = [0.0, 0,0]
    
    # numb2
    h_2a = [-0.1, y2]
    h_2b = [-0.1, 0,0]
    
    # numb - Brace
    curlyBrace.curlyBrace(fig, ax, h_1b, h_1a, k_r1, bool_auto=True, str_text='numb1', color='black', lw=1, int_line_num=1, fontdict=font)
    curlyBrace.curlyBrace(fig, ax, h_2b, h_2a, k_r1, bool_auto=True, str_text='numb2', color='black', lw=1, int_line_num=1, fontdict=font)
    
    ax.set_axis_off()
    
    ax.legend(bbox_to_anchor=(1.04,1), loc="upper left")
plt.tight_layout() 
plt.show()

enter image description here

答案 1 :(得分:0)

这是我使用Matplotlib,Pandas和NumPy的解决方案:

首先我加载数​​据,但是我将时间增量保留为秒,并从最小到最大排序:
代码:

df = pd.DataFrame({'timedelta':[75,80,55,20,45],
                   'numb1':[8,25,11,14,8],
                   'timedelta1': [55,60,45,15,30],
                   'numb2':[10,30,15,18,10],
                   'timedelta2': [45,50,35,10,20]})

df = df.sort_values(by='timedelta')
df

运行该代码后,这里是df

    timedelta   numb1   timedelta1  numb2   timedelta2
3   20          14      15          18      10
4   45          8       30          10      20
2   55          11      45          15      35
0   75          8       55          10      45
1   80          25      60          30      50

下一步,我将定义辅助函数,以将秒转换为分钟格式(稍后在xtick标签中使用)

def minSec(sec):
    minutes = int(sec/60)
    remSec = int(sec - 60*minutes)
    
    if (remSec == 0):
        remSec = '00'
    else:
        remSec = str(remSec)
    
    return str(minutes) + ':' + remSec

def minSec_arr(sec_arr):
    output  = []
    for i in range(sec_arr.shape[0]):
        output.append(minSec(sec_arr[i]))
        
    return output

最后,我们遍历df的所有行,并使用标签绘制适当的矩形图

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np

# Create MULTIPLE figures
for i in range(df.shape[0]):
    # Get initial data
    row = df.iloc[i,:]
    height = max(row.numb1, row.numb2)
    width = row.timedelta

    # Create figure
    fig, ax = plt.subplots()
    currentAxis = plt.gca()
    
    # Set basic layout
    plt.xlim(0, max(df.timedelta))
    plt.ylim(0, max(df.numb2))
    plt.title('Row ' + str(i))
    plt.xlabel('Time [mm:ss]')
    plt.ylabel('Number')
    
    # Create proper x ticks
    spaces = np.linspace(0, max(df.timedelta), 9)
    vals =  minSec_arr(spaces)
    plt.xticks(spaces, vals)

    # Create the main rectangle
    currentAxis.add_patch(Rectangle((0, 0), width, height, fill=True, color='r', alpha=1, ec='k'))
    axLabel = '(' + str(minSec(width)) + ',' + str(height) + ')'
    plt.annotate(axLabel, (width,height))
    
    # Create numb1 rectangle
    width = row.timedelta1
    height = row.numb1
    currentAxis.add_patch(Rectangle((0, 0), width, height, fill=True, color='b', alpha=1, ec='k'))
    axLabel = '(' + str(minSec(width)) + ',' + str(height) + ')'
    plt.annotate(axLabel, (width,height))
    
    # Create numb2 rectangle
    width = row.timedelta2
    height = row.numb2
    currentAxis.add_patch(Rectangle((0, 0), width, height, fill=True, color='g', alpha=0.4, ec='k'))
    axLabel = '(' + str(minSec(width)) + ',' + str(height) + ')'
    plt.annotate(axLabel, (width,height))
    
    plt.show()

以下是示例输出图形
Row1_Rect_Plot

希望我能完全理解您的问题