子图中每个标记中变量的数据值

Data value of a variable in each marker within subplots

我正在开发以下函数:extract_name_value() 生成一个步骤图,它采用 Python 中的 pandas DataFrame 的值,目前它工作正常,但是我想在每个标记中添加变量 points_axisyvalue 或 values_list 的值:Script Here

我尝试使用以下示例:Data value at each marker, Matplotlib scatter plot with different text at each data point or How to put individual tags for a matplotlib scatter plot?,这将是我想要的;我什至尝试过使用 plt.annotate(),但是值的数据并没有按照我想要的方式出现,而且我认为它会掩盖很多图表并且不会很好地欣赏。下面是我使用 plt.annotate():

的代码
    # Function to extract the Name and Value attributes
    def extract_name_value(signals_df, rootXML):
        # print(signals_df)
        names_list = [name for name in signals_df['Name'].unique()]
        num_names_list = len(names_list)
        num_axisx = len(signals_df["Name"])
        values_list = [value for pos, value in enumerate(signals_df["Value"])]
        print(values_list)
        points_axisy = signals_df["Value"]
        print(len(points_axisy))

        colors = ['b', 'g', 'r', 'c', 'm', 'y']
    
        # Creation Graphic
        fig, ax = plt.subplots(nrows=num_names_list, figsize=(20, 30), sharex=True)
        plt.suptitle(f'File XML: {rootXML}', fontsize=16,         fontweight='bold', color='SteelBlue', position=(0.75, 0.95))
        plt.xticks(np.arange(-1, num_axisx), color='SteelBlue', fontweight='bold')
        labels = ['value: {0}'.format(j) for j in values_list]
        print(labels)
        i = 1
        for pos, name in enumerate(names_list):
            # get data
            data = signals_df[signals_df["Name"] == name]["Value"]
            print(data)
            # get color
            j = random.randint(0, len(colors) - 1)
            # get plots by index = pos
            x = np.hstack([-1, data.index.values, len(signals_df) - 1])
            y = np.hstack([0, data.values, data.iloc[-1]])
            ax[pos].plot(x, y, drawstyle='steps-post', marker='o', color=colors[j], linewidth=3)
            ax[pos].set_ylabel(name, fontsize=8, fontweight='bold', color='SteelBlue', rotation=30, labelpad=35)
            ax[pos].yaxis.set_major_formatter(ticker.FormatStrFormatter('%0.1f'))
             ax[pos].yaxis.set_tick_params(labelsize=6)
             ax[pos].grid(alpha=0.4)
             i += 1

             for label, x, y in zip(labels, x, y):
             plt.annotate(label, xy=(x, y), xytext=(-20, 20), textcoords='offset points', ha='right', va='bottom', bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
                    arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))

        plt.show()

我得到的是拼接在不同位置的注释。

但是,我的代码需要什么来显示每个点的每个值?

我也一直在尝试使用 Matplotlib 参考中的代码,但无法完成:Marker Reference。非常感谢您,任何评论都有帮助。

我想应该和你的要求很接近了。我随机生成数据,然后使用 matplotlib.text 对其进行注释。它不是很漂亮,您可能想添加一些填充和更多改进,但我希望它能提供一个好主意!

如果两点距离太近,您可能需要在左侧注释一个,在右侧注释另一个,就像我对第一个点所做的​​那样。在你举的例子中我没有看到这种情况,所以没有处理。

函数place_label(label, xy, position, ax, pad=0.01) 将标签放在您想要的位置。代码的其余部分使用随机生成的数据来证明它可以工作。

import random
import numpy as np
import matplotlib.pyplot as plt

# function that places the label give the desired position
def place_label(label, xy, position, ax, pad=0.01):

  # annotate in the initial position, xy is the top right corner of the bounding box
  t_ = ax.text(x=xy[0], y=xy[1], s=label, fontsize=16)

  # find useful values
  tbb = t_.get_window_extent(renderer=rend)
  abb = ax.get_window_extent(renderer=rend)
  a_xlim, a_ylim = ax.get_xlim(), a_.get_ylim()

  # now adjust the position if needed
  new_xy = [xy[0], xy[1]]

  relative_width = tbb.width/abb.width * (a_xlim[1] - a_xlim[0])
  pad_x = pad * (a_xlim[1] - a_xlim[0])
  assert(position[0] in ['l', 'c', 'r'])
  if position[0] == 'c':
    new_xy[0] -= relative_width/2
  elif position[0] == 'l':
    new_xy[0] -= relative_width + pad_x
  else:
    new_xy[0] += pad_x

  relative_height =  tbb.height/abb.height * (a_ylim[1] - a_ylim[0])
  pad_y = pad * (a_ylim[1] - a_ylim[0])
  assert(position[1] in ['b', 'c', 't'])
  if position[1] == 'c':
    new_xy[1] -= relative_height/2
  elif position[1] == 'b':
    new_xy[1] -= relative_height + pad_y
  else:
    new_xy[1] += pad_y

  t_.set_position(new_xy)

  return t_

# generate data, plot it and annotate it!
axes_qty = 9
axes_gap = 0.035

fig = plt.figure(figsize=(10, 8))
ax = [plt.axes([axes_gap, axes_gap/2 + i*(1/axes_qty), 1-2*axes_gap, 1/axes_qty-axes_gap]) for i in range(axes_qty)]
rend = fig.canvas.get_renderer()

for a_ in ax:
  x_ = [random.randint(0, 10) for _ in range(5)]
  x_ = np.unique(x_)
  y_ = [random.randint(0, 12) for _ in x_]
  # as x is shared, we set the limits in advance, otherwise the adjustments won't be accurate
  a_.set_xlim([-0.5, 10.5])
  
  # plotting the data
  data_ = [[x_[0], y_[0]]]
  for i in range(1, len(x_)):
    data_ += [[x_[i-1], y_[i]], [x_[i], y_[i]]]
  a_.plot([d[0] for d in data_], [d[1] for d in data_])

  mid_y = 0.5 * (a_.get_ylim()[0] + a_.get_ylim()[1])

  # now let's label it
  for i in range(len(x_)):
    # decide what point we annotate
    if i == 0:
      xy = [x_  [0], y_[0]]
    else:
      xy = [x_[i-1], y_[i]]

    # decide its position
    position_0 = 'l' if i == 0 else 'r'
    position_1 = 'b' if xy[1] > mid_y else 't'

    place_label(label=str(xy[1]), xy=xy, position=position_0+position_1, ax=a_)

plt.show()

您可以在循环中使用 plt.annotate 函数来解决您的问题。

我随机生成了一些数据并将其绘制为单个图。你可以在子图中做同样的事情,功能是一样的。

# sample data points for the plot
x=np.arange(1,10)
y=np.linspace(20,40,9)

plt.figure(figsize=[15,5],dpi=200)
plt.plot(x,y,drawstyle='steps-post', marker='o')
# using annotate function to show the changepoints in a loop 
for i in range(len(x)):
    # I rounded the y values as string and used the same x and y coords as the locations
    # next we can give a constant offset points to offset the annotation from each value
    # here I used (-20,20) as the offset values
    plt.annotate(f"{str(round((y[i])))}",(x[i],y[i]),xycoords='data',
                 xytext=(-20,20), textcoords='offset points',color="r",fontsize=12,
                 arrowprops=dict(arrowstyle="->", color='black'))

如果你不想要箭头,你可以移除箭头道具。

已编辑

我使用了您的 GitHub 存储库中的 example1.xml 文件并稍微编辑了函数。我所做的只是为您的函数添加一个循环和一个 if-else 条件。

# Initial part is same as yours
names_list = [name for name in signals_df['Name'].unique()]
num_names_list = len(names_list)
num_axisx = len(signals_df["Name"])
values_list = [value for pos, value in enumerate(signals_df["Value"])]
points_axisy = signals_df["Value"]
colors = ['b', 'g', 'r', 'c', 'm', 'y']
# start new figure
plt.figure(figsize=[20,28],dpi=200)
#start a loop with the subplots
for i in range(len(names_list)):
    # subplot has 14 rows, 1 column and the i+1 represents the i'th plot
    plt.subplot(num_names_list,1,i+1)
    # choose color
    col=np.random.randint(0, len(colors) - 1)
    # get the locations of the values with the similar name in your list
    locs=signals_df['Name']==names_list[i]
    # get the values in those locations
    data=signals_df['Value'][locs]
    # arrange the x and y coordinates
    x = np.hstack([-1, data.index.values, len(signals_df) - 1])
    y = np.hstack([0, data.values, data.iloc[-1]])
    # plot the values as usual
    plt.plot(x, y, drawstyle='steps-post', marker='o', color=colors[col], linewidth=3)
    plt.ylabel(names_list[i], fontsize=8, fontweight='bold', color='SteelBlue', rotation=30, labelpad=35)
    plt.grid(alpha=0.4)
    # this loop is for annotating the values 
    for j in range(len(x)):
        # I found it is better to alternate the position of the annotations 
        # so that they wont overlap for the adjacent values
        if j%2==0:
            # In this condition the xytext position is (-20,20)
            # this posts the annotation box over the plot value
            plt.annotate(f"Val={round((y[j]))}",(x[j],y[j]),xycoords='data',
                         xytext=(-20,20), textcoords='offset points',color="r",fontsize=8,
                         arrowprops=dict(arrowstyle="->", color='black'),
                        bbox=dict(boxstyle='round', pad=0.5, fc='yellow', alpha=0.5))
        else:
            # In this condition the xytext position is (-20,-20)
            # this posts the annotation box under the plot value
            plt.annotate(f"Val={round((y[j]))}",(x[j],y[j]),xycoords='data',
                 xytext=(-20,-20), textcoords='offset points',color="r",fontsize=8,
                 arrowprops=dict(arrowstyle="->", color='black'),
                         bbox=dict(boxstyle='round', pad=0.5, fc='yellow', alpha=0.5))

新函数结果

希望有用。