简体   繁体   English

将文本侧边栏添加到 matplotlib plot

[英]Add a text sidebar to matplotlib plot

How would I go about adding a multiline text sidebar to a matplotlib chart including key information我将如何 go 向包含关键信息的 matplotlib 图表添加多行文本侧边栏在此处输入图像描述

I would like to add a text sidebar similar to the one on the right side of this chart where I could include more information about the presented chart.我想添加一个类似于此图表右侧的文本侧边栏,我可以在其中包含有关所显示图表的更多信息。 This sidebar should have 0 padding between the main graph and the sidebar.此侧边栏应在主图和侧边栏之间有 0 填充。 I should be able to use different colors and fonts on the sidebar to highlight certain elements.我应该能够在侧边栏上使用不同的 colors 和 fonts 来突出显示某些元素。 The following is my code I used for generating the line chart:以下是我用于生成折线图的代码:

plt.style.use("custom_style.mplstyle")
fig = plt.figure(figsize=(16, 9), dpi=240)
ax = fig.add_subplot(111)

color = "#52cc00" if float(dif) >= 0 else "#cc5240"
ax.plot_date(df["time"], df["close"], fmt=color, xdate=False, marker=None, linewidth=3, linestyle="-")

dateFMT = mdates.DateFormatter(r'%I%p')
ax.xaxis.set_major_formatter(dateFMT)
chart_name = name if isinstance(chart_name, pd.core.series.Series) else chart_name
plt.title(f"{chart_name}: {close} [{dif}%]")

plt.autoscale(tight=True)
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backend_bases import MouseButton  as mevent
from matplotlib.backend_bases import Event
from matplotlib.font_manager import FontProperties

class Cursor:
    """
    A cross hair cursor.
    """
    def __init__(self, ax, horzdata,verticaldata,ax2):
        self.ax = ax
        self.ax2 = ax2
        self.verticaldata = verticaldata
        self.horzdata = horzdata
        self.x1 = 0
        self.y1 = 0
        self.x2 = 0
        self.y2 = 0  
        
        self.actCuror = 'D'
        
        self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
        self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
        
        self.horizontal_line_2 = ax.axhline(color='b', lw=1, ls='solid')
        self.vertical_line_2 = ax.axvline(color='b', lw=1, ls='solid')
        
        # text location in axes coordinates
        self.text_1 = ax2.text (0.05, 0.95,'P0(', transform=ax2.transAxes)
        self.text_2 = ax2.text (0.05, 0.9, 'P1(', transform=ax2.transAxes)
        self.Text_3 = ax2.text (0.05, 0.85,'dP(', transform=ax2.transAxes)
        
    def set_cross_hair_visible(self, visible):
        need_redraw = self.horizontal_line.get_visible() != visible
        self.horizontal_line.set_visible(visible)
        self.vertical_line.set_visible(visible)
        self.horizontal_line_2.set_visible(visible)
        self.vertical_line_2.set_visible(visible) 
        
        self.text_1.set_visible(visible)
        self.text_2.set_visible(visible)
        self.Text_3.set_visible(visible)
        
        return need_redraw
    
    def on_mouse_click(self,event):
        #print(event)
        if event.name == 'button_press_event':
                
            if event.button == mevent.LEFT:
                self.actCuror = "A" 
                self.horizontal_line.set_ydata(event.ydata)
                self.vertical_line.set_xdata(event.xdata)           
            elif event.button == mevent.RIGHT:
                self.actCuror = 'B'
                self.horizontal_line_2.set_ydata(event.ydata)
                self.vertical_line_2.set_xdata(event.xdata)
        else:
            self.actCuror = 'D'
            print("no move")
        self.ax.figure.canvas.draw()
     
    def on_mouse_move(self, event):
        #print(event.x)
        #print(event.y)
        #print(event.xdata)
        #print(event.ydata)
        if not event.inaxes:
            pass
            #need_redraw = self.set_cross_hair_visible(False)
            #if need_redraw:
            #    self.ax.figure.canvas.draw()
        else:
            #print(self.__class__.__name__)
            self.set_cross_hair_visible(True)
            x = event.xdata
            xindx = np.where(self.horzdata >= x)
            #print(xindx[0][0])
            #y = event.ydata
            y = self.verticaldata[xindx[0][0]]
            # update the line positions
            
            if self.actCuror == "A":
                self.x1 = x
                self.y1 = y
                self.horizontal_line.set_ydata(y)
                self.vertical_line.set_xdata(x)
                self.text_1.set_text('P0 = (%1.2f, %1.2f)' % (x, y))
            elif self.actCuror == 'B':  
                self.x2 = x
                self.y2 = y  
                self.horizontal_line_2.set_ydata(y)
                self.vertical_line_2.set_xdata(x)
                self.text_2.set_text('P1 = (%1.2f, %1.2f)' % (x, y))
            self.Text_3.set_text('dP = (%1.2f, %1.2f)' % (abs(self.x1- 
            self.x2), abs(self.y2-self.y1)))
            self.ax.figure.canvas.draw()


x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)    
fig.set_constrained_layout_pads( hspace=0, wspace=0)
ax[0].set_title('Simple cursor')
ax[0].plot(x, y, 'o')
ax[0].set_position([0.05, 0.05, 0.75, 0.9])

ax[1].set_position([0.82, 0.05, 0.15, 0.9])
ax[1].set_xticks([])
ax[1].set_yticks([])

#plt.subplots_adjust()

font0 = FontProperties()
alignment = {'horizontalalignment': 'center', 'verticalalignment':\
baseline'}

# Show family options    
families = ['serif', 'sans-serif', 'cursive', 'fantasy', 'monospace']
plt.figtext(0.8, 0.5, 'bold italic', fontproperties=font0, **alignment)

cursor = Cursor(ax[0],x,y, ax[1])


fig.canvas.mpl_connect('motion_notify_event', cursor.on_mouse_move)
fig.canvas.mpl_connect('button_press_event', cursor.on_mouse_click)
fig.canvas.mpl_connect('button_release_event', cursor.on_mouse_click)

plt.show()
print("done")

################## ##################

""" just an idea make two subplots side by side and use the right subplot as a text area """ 只是一个想法让两个子图并排并使用正确的子图作为文本区域

check below code I was trying to make two crosshair coursers with measurement I created two subplots on the same figure with ases ax[0] for drawing and ax[1] to hold text查看以下代码

as per my understanding the figure area size is treated as 1x1据我了解,图形区域大小被视为 1x1

I used set_position to adjust the axis size and location for example ax[0].set_position([0.05, 0.05, 0.75, 0.9])我使用set_position来调整轴的大小和位置,例如ax[0].set_position([0.05, 0.05, 0.75, 0.9])

with set the drawing axis at points x =.05, y =.05, width = 0.75 & height = 0.9, remeber complet figure is 1x1在点 x =.05, y =.05, width = 0.75 & height = 0.9 处设置绘图轴,请记住完整图为 1x1

also ax[1] for text is positioned according to ax[1].set_position([0.82, 0.05, 0.15, 0.9])文本的 ax[1] 也是根据ax[1].set_position([0.82, 0.05, 0.15, 0.9])定位的

I removed the axis ticks to appear as a box我删除了轴刻度以显示为一个框

  • below lines下线

     self.text_1 = ax2.text (0.05, 0.95,'P0(', transform=ax2.transAxes) self.text_2 = ax2.text (0.05, 0.9, 'P1(', transform=ax2.transAxes) self.Text_3 = ax2.text (0.05, 0.85,'dP(', transform=ax2.transAxes)

will show text in the ax[1] area, here dimension are relative to ax[1] area not full figure area将在 ax[1] 区域显示文本,这里的尺寸是相对于 ax[1] 区域而不是全图区域

please check below code on the drawing axis press and hold right/left mouse key and watch the measurement on the ax[1] area请检查绘图轴上的以下代码按住鼠标左键并观察 ax[1] 区域上的测量值

  • remember to place a break point at the last line and run in debug mode so u can play with the code记得在最后一行放置一个断点并在调试模式下运行,这样你就可以使用代码了

""" """

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM