Bagaimana cara memplot batang yang berbeda untuk setiap nilai dalam kolom, di mana setiap plot sesuai dengan nilai di kolom lain?

Dec 04 2020

Saya memiliki dataframe ini seperti yang ditunjukkan di bawah ini:

data = [['AK','Coal',24457],
['AK','Natural ',222867],
['AK','Other ',15],
['AK','Petro',83848],
['AL','Coal ',169877],
['AL','Natural ',10692],
['AL','Other ',2631],
['AL','Petro',235853]]

df = pd.DataFrame(data, columns = ['STATE','ENERGY','CONSUME']) 

Saya mencoba memplotnya pada grafik, yang perlu terlihat seperti gambar ini:

Setiap bilah sesuai dengan nilai 'KONSUMSI' untuk masing-masing 'ENERGI'. Ini seperti mengelompokkan nilai berdasarkan 'NEGARA' dan menyusun batang yang berbeda berdasarkan 'ENERGI'. Jadi pada dasarnya, setiap 'NEGARA' akan memiliki 4 batang yang menunjukkan 4 nilai 'ENERGI' yang berbeda. Saya memang mencoba beberapa hal, tetapi tidak berhasil seperti yang saya inginkan.

Jawaban

Pygirl Dec 04 2020 at 15:30

Saya baru saja memodifikasi kode yang diberikan oleh Scott Boston di salah satu jawabannya. Lihatlah jawaban itu juga.

import pandas as pd
import matplotlib.pyplot as plt
from itertools import groupby
import numpy as np 
%matplotlib inline

data = [['AK','Coal',24457],
['AK','Natural ',222867],
['AK','Other ',15],
['AK','Petro',83848],
['AL','Coal ',169877],
['AL','Natural ',10692],
['AL','Other ',2631],
['AL','Petro',235853]]
df = pd.DataFrame(data, columns = ['STATE','ENERGY','CONSUME']) 
df = df.set_index(['STATE','ENERGY', 'STATE'])['CONSUME'].unstack()


def add_line(ax, xpos, ypos):
    line = plt.Line2D([xpos, xpos], [ypos + .1, ypos],
                      transform=ax.transAxes, color='gray')
    line.set_clip_on(False)
    ax.add_line(line)

def label_len(my_index,level):
    labels = my_index.get_level_values(level)
    return [(k, sum(1 for i in g)) for k,g in groupby(labels)]

def label_group_bar_table(ax, df):
    ypos = -.1
    scale = 1./df.index.size
    for level in range(df.index.nlevels)[::-1]:
        pos = 0
        for label, rpos in label_len(df.index,level):
            lxpos = (pos + .5 * rpos)*scale
            ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes)
            add_line(ax, pos*scale, ypos)
            pos += rpos
        add_line(ax, pos*scale , ypos)
        ypos -= .1

ax = df.plot(kind='bar')
#Below 2 lines remove default labels
ax.set_xticklabels('')
ax.set_xlabel('')
label_group_bar_table(ax, df)