1

enter image description here

How do I create a pointer at the intersection between two lines?

Derek O
  • 16,770
  • 4
  • 24
  • 43
  • Can you attach the code you used to generate this image, as well as the DataFrame or a sample of the DataFrame? – Derek O May 07 '21 at 04:08

1 Answers1

0

The only difference between your question and Plotly: How to find and annotate the intersection point between two lines? seems to be that your case has multiple intersectoins. You can still use the very same approach described here and then take into account multiple annotations for multiple intersections with:

for x, y in zip(x,y):
    fig.add_annotation(x=x, y=y,
                       text = 'lines intersect at x = ' + str(round(x, 2)) + ' and y = ' + str(round(y, 2)),
                       font=dict(family="sans serif", size=18, color="black"),
                        ax=0,
                        ay=-100,
                        showarrow=True,
                        arrowhead=1)

enter image description here

Complete code:

import pandas as pd
import plotly.graph_objects as go
import numpy as np
# import dash


# sample dataframe
df = pd.DataFrame()
df['x'] = np.arange(4) +1
df['y1'] = df['x']**3
df['y2'] = [10+val**2.2 for val in df['x']]

df2 = pd.DataFrame({'x':[5,6,7],
                    'y1':[60, 50, 10],
                    'y2':[26,20,19]})

df = pd.concat([df, df2])

# intersection stuff
def _rect_inter_inner(x1,x2):
    n1=x1.shape[0]-1
    n2=x2.shape[0]-1
    X1=np.c_[x1[:-1],x1[1:]]
    X2=np.c_[x2[:-1],x2[1:]]
    S1=np.tile(X1.min(axis=1),(n2,1)).T
    S2=np.tile(X2.max(axis=1),(n1,1))
    S3=np.tile(X1.max(axis=1),(n2,1)).T
    S4=np.tile(X2.min(axis=1),(n1,1))
    return S1,S2,S3,S4

def _rectangle_intersection_(x1,y1,x2,y2):
    S1,S2,S3,S4=_rect_inter_inner(x1,x2)
    S5,S6,S7,S8=_rect_inter_inner(y1,y2)

    C1=np.less_equal(S1,S2)
    C2=np.greater_equal(S3,S4)
    C3=np.less_equal(S5,S6)
    C4=np.greater_equal(S7,S8)

    ii,jj=np.nonzero(C1 & C2 & C3 & C4)
    return ii,jj

def intersection(x1,y1,x2,y2):

    ii,jj=_rectangle_intersection_(x1,y1,x2,y2)
    n=len(ii)

    dxy1=np.diff(np.c_[x1,y1],axis=0)
    dxy2=np.diff(np.c_[x2,y2],axis=0)

    T=np.zeros((4,n))
    AA=np.zeros((4,4,n))
    AA[0:2,2,:]=-1
    AA[2:4,3,:]=-1
    AA[0::2,0,:]=dxy1[ii,:].T
    AA[1::2,1,:]=dxy2[jj,:].T

    BB=np.zeros((4,n))
    BB[0,:]=-x1[ii].ravel()
    BB[1,:]=-x2[jj].ravel()
    BB[2,:]=-y1[ii].ravel()
    BB[3,:]=-y2[jj].ravel()

    for i in range(n):
        try:
            T[:,i]=np.linalg.solve(AA[:,:,i],BB[:,i])
        except:
            T[:,i]=np.NaN


    in_range= (T[0,:] >=0) & (T[1,:] >=0) & (T[0,:] <=1) & (T[1,:] <=1)

    xy0=T[2:,in_range]
    xy0=xy0.T
    return xy0[:,0],xy0[:,1]

# plotly figure
x,y=intersection(np.array(df['x'].values.astype('float')),np.array(df['y1'].values.astype('float')),
                 np.array(df['x'].values.astype('float')),np.array(df['y2'].values.astype('float')))

fig = go.Figure(data=go.Scatter(x=df['x'], y=df['y1'], mode = 'lines'))
fig.add_traces(go.Scatter(x=df['x'], y=df['y2'], mode = 'lines'))
fig.add_traces(go.Scatter(x=x, y=y,
                          mode = 'markers',
                          marker=dict(line=dict(color='black', width = 2),
                                      symbol = 'diamond',
                                      size = 14,
                                      color = 'rgba(255, 255, 0, 0.6)'),
                         name = 'intersect'),
              )

for x, y in zip(x,y):
    fig.add_annotation(x=x, y=y,
                       text = 'lines intersect at x = ' + str(round(x, 2)) + ' and y = ' + str(round(y, 2)),
                       font=dict(family="sans serif", size=18, color="black"),
                        ax=0,
                        ay=-100,
                        showarrow=True,
                        arrowhead=1)

fig.show()
vestland
  • 55,229
  • 37
  • 187
  • 305