如何根据数字符号更改matplotlib中的标记

问题描述:

概述

我有一些类似的数据:

  • X值:频率范围
  • Y值:float可以为正或负的值
    • 如果您好奇,则Y值为电抗
    • X values: range of frequencies
    • Y values: float value that can be positive or negative
      • The Y-value is electrical reactance, if you're curious

      我用对数-对数图表示数据.由于您只能取正数的对数,因此我绘制abs(Y-value).

      I represent the data in a log-log plot. Since you can only take the logarithm of a positive number, I plot abs(Y-value).

      在对数-对数图上,我想通过更改标记符号来表示原始数字的符号:

      On the log-log plot, I would like to represent the original number's sign by changing the marker symbol:

      • +标记(如果符号为+
      • )
      • -标记(如果符号为-
      • )
      • + marker if sign was +
      • - marker if sign was -

      通常:下面,我放置了当前的方法.我想做得更好".希望matplotlib有更标准的方法来实现这一点.

      Generally: below I have placed my current method. I would like to "do it better". Hopefully matplotlib has a more standard way of doing this.

      详细信息

      目前,这是我的情节:

      这是我当前代码的相似之处(请注意:数据是从设备中提取的,因此在这种情况下,我只使用了random.uniform):

      Here is some semblance of my current code (note: the data was pulled from equipment, so I just used random.uniform in this case):

      import numpy as np
      import matplotlib.pyplot as plt
      from random import uniform
      
      
      # Generating data
      num_pts = 150
      freq_arr = np.logspace(start=2, stop=6, num=num_pts, base=10)
      reactance_arr = [uniform(-1000,1000) for i in range(num_pts)]
      abs_reactance_arr = [abs(i) for i in reactance_arr]
      reactance_signed_marker = [1 if reactance_arr[i] >= 0 else -1 for i in range(len(reactance_arr))]
      
      # Taken from here: https://stackoverflow.com/questions/28706115/how-to-use-different-marker-for-different-point-in-scatter-plot-pylab
      x = np.array(freq_arr)
      y = np.array(abs_reactance_arr)
      grouping = np.array(reactance_signed_marker)
      
      # Plotting
      fig1, ax1 = plt.subplots()
      
      positives_line = ax1.scatter(
          x[grouping == 1], 
          y[grouping == 1], 
          s=16, 
          marker="+", 
          label="Reactance",
      )
      
      # Match color between the two plots
      col = positives_line.get_facecolors()[0].tolist()
      
      ax1.scatter(
          x[grouping == -1],
          y[grouping == -1],
          s=16,
          marker="_",
          label="Reactance",
          color=col,
      )
      
      ax1.set_xlim([freq_arr[0], freq_arr[-1]])
      ax1.set_xscale("log")
      ax1.set_xlabel("Frequency (Hz)")
      ax1.set_yscale("log")
      ax1.set_ylabel("Value (Ohm)")
      ax1.legend()
      ax1.set_title("Reactance")
      

      我该如何做得更好?目前,这感觉非常手动.我想知道:

      How can I do this better? Currently, this feels very manual. I am wondering:

      • 是否有更好的方法将-+值解析为标记?
        • 当前方法非常麻烦:1.绘制+,2.提取颜色,3.绘制具有相同颜色的-
        • Is there a better way to parse - and + values into markers?
          • The current way is quite cumbersome with 1. plotting +, 2. extracting color, 3. plotting - with the same color

我在

I proposed a scatter with multiple markers in iterating markers in plots. Applying it here would look like:

import numpy as np
import matplotlib.pyplot as plt

def mscatter(x, y, ax=None, m=None, **kw):
    import matplotlib.markers as mmarkers
    if not ax: ax=plt.gca()
    sc = ax.scatter(x,y,**kw)
    if (m is not None) and (len(m)==len(x)):
        paths = []
        for marker in m:
            if isinstance(marker, mmarkers.MarkerStyle):
                marker_obj = marker
            else:
                marker_obj = mmarkers.MarkerStyle(marker)
            path = marker_obj.get_path().transformed(
                        marker_obj.get_transform())
            paths.append(path)
        sc.set_paths(paths)
    return sc

# Generating data
num_pts = 150
freq_arr = np.logspace(start=2, stop=6, num=num_pts, base=10)
reactance_arr = np.random.uniform(-1000,1000,num_pts)

x = np.array(freq_arr)
y = np.abs(reactance_arr)
markers = np.array(["_", "+"])[(reactance_arr >= 0).astype(int)]

# Plotting
fig1, ax1 = plt.subplots()

mscatter(x, y, ax=ax1, s=16, m = markers, label="Reactance")

ax1.set_xlim([freq_arr[0], freq_arr[-1]])
ax1.set_xscale("log")
ax1.set_xlabel("Frequency (Hz)")
ax1.set_yscale("log")
ax1.set_ylabel("Value (Ohm)")
ax1.legend()
ax1.set_title("Reactance")

plt.show()