Search code examples
pythonloopsfor-loopplotlynested-loops

My first plot overlapping my second plot on nested for loop (Python/Plotly)


I'm having a hard time understanding this nested for-loop problem, I want to make automated plot using the nested for-loop in plotly, but my first graph resulted from first loop overlapping my second graph

Here is my code

#Read all the well log data
paths = sorted(glob.glob(os.path.join("well_contoh", "*.LAS")))
well_df = [0]*2
for i in range(len(paths)):
    well = lasio.read(paths[i])
    df = well.df()
    well_df[i] = df.reset_index()
well1, well2 = well_df #only 2 wells


#Automatic well log plots if any well log data comes in in the future
html_list = []
dataframe_well = {'Well 1F':well1, 'Well 2F':well2} #defining dataframe

wells = ['Well 1F','Well 2F'] #list of well for looping

#list of longitude and latitude for well 1 and well 2 respectively (a dummy coordinate)
Longitude = [96.083956, 96.356427]
Latitude = [5.456862, 5.328133]

#list of logs and their colors
logs = ['CALI', 'GR', 'RT', 'NPHI', 'RHOB', 'DT']
colors = ['black', 'green', 'red', 'royalblue', 'mediumaquamarine', 'goldenrod']

#plot
log_cols = np.arange(1,8)
logplot = make_subplots(rows=1, cols=len(logs), shared_yaxes = True, specs=[[{},{},{},{},{},{}]], 
                        horizontal_spacing=0.005)

for i in range(len(wells)):
    for j in range(len(logs)):
        if j == 2:
            logplot.add_trace(go.Scatter(x=dataframe_well[wells[i]][logs[j]], y=dataframe_well[wells[i]]['DEPTH'], name=logs[j], line_color=colors[j]), row=1, col=log_cols[j])
            logplot.update_xaxes(type='log', row=1, col=log_cols[j], title_text=logs[j], tickfont_size=12, linecolor='#585858')
        else:
            logplot.add_trace(go.Scatter(x=dataframe_well[wells[i]][logs[j]], y=dataframe_well[wells[i]]['DEPTH'], name=logs[j], line_color=colors[j]), row=1, col=log_cols[j])
            logplot.update_xaxes(col=log_cols[j], title_text=logs[j], linecolor='#585858')
    
    logplot.update_xaxes(showline=True, linewidth=2, linecolor='black', mirror=True, ticks='inside', tickangle=45)
    logplot.update_yaxes(tickmode='linear', tick0=0, dtick=250, showline=True, linewidth=2, ticks='outside', mirror=True, linecolor='black')
    logplot.update_yaxes(row=1, col=1, autorange='reversed')
    logplot.update_layout(height=700, width=800, showlegend=False)
    logplot.update_layout(
                 title_text="Example of " + '<b>' + str(wells[i]) + '</b>', #Add a chart title
                 title_font_family="Arial",
                 title_font_size = 25, title_x=0.5)

    logplot.write_html('fig'+str(wells[i])+'.html') # the plot is automatically saved as html

    #list html plots to show what pop up folium should show on the map
    html_list.append('fig'+str(wells[i])+'.html')

and the resulted plot for the second iterate, which Well 2F (overlapped image), is this

Overlapping image

the plot should be something like this (non-overlapping image)

non-overlapping image

Well 2F plot seems to be overlapped by Well 1F plot, which is the problem here must be the nested loop that I use for

Here is the dummy data if someone wanna try it

https://drive.google.com/drive/folders/1DCnNpXpgqVCYNaMiD7FX6CpVqsOl3mkX?usp=share_link

Anyone has the idea how to solve this problem? Thanks!


Solution

  • Found the solution, if you want to plot using Plotly and for-looping it to make it automated multiple plot by only using single code run, you have to define it as a new function and loop through your defined function, and you must clear the plot content before turn into second loop, otherwise the second plot will be overlapped by first plot

    in the first loop, put this before entering the second loop

    logplot.data = []
    

    here is the full code

    def wellplot(wellx, title): #Update (defined function)
        for j in range(len(logs)):
            if j == 2: #change to log for RT
                logplot.add_trace(go.Scatter(
                    x=wellx[logs[j]], 
                    y=wellx['DEPTH'], 
                    name=logs[j], 
                    line_color=colors[j]), 
                                row=1, col=log_cols[j])
                logplot.update_xaxes(type='log', row=1, col=log_cols[j], title_text=logs[j], tickfont_size=12, linecolor='#585858')
            else:
                logplot.add_trace(go.Scatter(
                    x=wellx[logs[j]],
                    y=wellx['DEPTH'], 
                    name=logs[j], 
                    line_color=colors[j]), row=1, col=log_cols[j])
                logplot.update_xaxes(col=log_cols[j], title_text=logs[j], linecolor='#585858')
    
        logplot.update_xaxes(showline=True, linewidth=2, linecolor='black', mirror=True, ticks='inside', tickangle=45)
        logplot.update_yaxes(tickmode='linear', tick0=0, dtick=250, showline=True, linewidth=2, ticks='outside', mirror=True, linecolor='black')
        logplot.update_yaxes(row=1, col=1, autorange='reversed')
        logplot.update_layout(height=700, width=700, showlegend=False)
        logplot.update_layout(
                    title_text="Example of " + '<b>' + title + '</b>', #Add a chart title
                    title_font_family="Arial",
                    title_font_size = 25, title_x=0.5)
        
        logplot.write_html('fig'+title+'.html') # the plot is automatically saved as html
        #list html plots to show what pop up folium should show on the map
        html_list.append('fig'+title+'.html')
        logplot.show()
    
    for i in range(len(wells)):
        logplot.data = [] #put this to clear the plot content (in order to make it non-overlapping)
        wellplot(dataframe_well[wells[i]], wells[i])