Создайте столбчатую диаграмму, чьи столбцы заполнены в процентах по отношению к максимуму или минимуму - PullRequest
3 голосов
/ 04 июня 2019

У меня есть данные о механических свойствах материала, прошедшего циклы термообработки.Гистограмма сгруппирована по каждому циклу с тремя свойствами: предел текучести, растяжение и удлинение.Предел текучести и предел прочности на разрыв имеют одинаковую ось y, а удлинение - на оси второго y.Предел текучести и предел прочности при растяжении имеют максимальные значения, а относительное удлинение - минимальное.Вместо того, чтобы использовать контрольные линии для минимального и максимального значений, я бы хотел, чтобы столбцы заполнялись в процентах от максимального минимального значения.

Я использую pandas для создания фрейма данных с .plot, а color = None и edgecolor для создания "пустых" баров.Тем не менее, edgecolor устанавливает цвет для каждой группы.

Я пробовал штриховку и заливку, но мне не посчастливилось выяснить, как заполнить только процентную долю.

Я также не хочу, чтобы df ["y_norm"]показать в каждой группе.В этом столбце содержится только соотношение, в котором столбец должен быть заполнен цветом.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from io import StringIO

s=StringIO("""     Yield     UTS     Elongation
T1     10.5     25.3     30.2
T2     10.8     26.3     30.3
T3     11.0     26.5     30.2
T4     11.5     27.2     30.4
T5     20.1     30.2     22.3
T6     24.7     31.2     19.0
T7     19.0     27.1     19.6
T8     12.2     21.7     23.4
T9     8.00     18.3     31.4""")

Ymax=float(16.0) #Yield strength maximum limit
UTSmax=float(22.0) #Ultimate Tensile Strengh maximum limit
Elmin=float(22.0) #Percent Elongation minimum limit

df = pd.read_csv(s, index_col=0, delimiter=' ',skipinitialspace=True)

df_scale=pd.DataFrame()
df_scale["y_norm"]=round(Ymax/df["Yield"],2)
df_scale["y_norm"]=df_scale["y_norm"].where(df_scale["y_norm"] < 1, 1)

#--progres bar for Ultimate Tensile Strength Maximum Limit-----
df_scale["T_norm"]=round(UTSmax/df["UTS"],2)
df_scale["T_norm"]=df_scale["T_norm"].where(df_scale["T_norm"]<1,1)

#--progres bar for Elongation Minimum Limit-----
df_scale["El_norm"]=round(Elmin/df["Elongation"],2)
df_scale["El_norm"]=df_scale["El_norm"].where(df_scale["El_norm"]>1,1)
df_scale["El_norm"]=df_scale["El_norm"].where(df_scale["El_norm"] 
<1,abs(df_scale["El_norm"]-2))

M_props=df.plot(kind="bar",secondary_y="Elongation",rot=0, 
edgecolor="rgb",color="None")
M_props.set_ylabel('KSI',rotation=0)
M_props.right_ax.set_ylabel('% El')
M_props.right_ax.set_ylim([10,40])

plt.show()

В результатах должны отображаться только последние две группы, T8 и T9, как полностью заполненные столбцы.

1 Ответ

1 голос
/ 04 июня 2019

IIUC, вам необходимо снова умножить y_norm и перерисовать:

# columns to draw:
col2draw = df.columns[:-1]

fig, M_props = plt.subplots(figsize=(10,6))

# draw the full-length empty bars
df[col2draw].plot(kind="bar",secondary_y="Elongation",
                         rot=0, edgecolor="k", ax=M_props,
                         color="None",
                         legend=False)

# fill the bars based on y_norm
(df[col2draw].apply(lambda x: x*df['y_norm'])
                    .plot(kind="bar",
                          secondary_y="Elongation",
                          rot=0,
                          ax=M_props)
)

M_props.set_ylabel('KSI',rotation=0)
M_props.right_ax.set_ylabel('% El')
M_props.right_ax.set_ylim([10,40])
plt.show()

Выход:

enter image description here


Обновление: если у вас разные шкалы для столбцов:

# create a scale dataframe, note the columns and index
df_scale = pd.DataFrame(columns=df.columns,
                        index=df.index)

# compute the scales, here we assign it randomly with seed
np.random.seed(1)
df_scale = np.random.uniform(0.5,1,(len(df),3))

# plot as previously
fig, M_props = plt.subplots(figsize=(10,6))

# draw the full-length empty bars
df.plot(kind="bar",secondary_y="Elongation",
                         rot=0, edgecolor="k", ax=M_props,
                         color="None",
                         legend=False)

# fill the bars based on y_norm
((df*df_scale).plot(kind="bar",
                  secondary_y="Elongation",
                  ax=M_props)
)

M_props.set_ylabel('KSI',rotation=0)
M_props.right_ax.set_ylabel('% El')
M_props.right_ax.set_ylim([10,40])
plt.show()

Вывод: enter image description here

...