Stimulation Charts – Python Coding Series

While @fauxright has been continuing to add high level financial analysis and examples, I wanted to step back for a moment and do an introductory level post. In this post, I will cover how to take those CSV files you have accumulated through years of fracturing and give them some new life. Some essential skills will be covered that will be repeated in many future projects. With that, lets crack the valve and start downhole.


Getting Started

First, we need to pull those CSV files into Python and analyze what columns we want to work with.

The data can be found here and here.


Load the Data

The Pandas library has a straightforward way for us to transform the CSV immediately into a dataframe (think table of data) that we can use. Calling ‘pd.read_csv‘ function loads our CSV data into the stageSeven variable. Next, use the .head() command to print the top 5 rows of data for our own exploration.

import pandas as pd

...

# Load our CSV file into a pandas dataframe
stageSeven = pd.read_csv('Stage 7.csv')

print(stageSeven.head())

Checking the Results

After checking the results that have been printed in our development environment, let’s make something tangible by plotting a column. From the previous look at the data, I know that ‘Date‘ and ‘Time‘ has been separated into two different columns.

For cleanliness, I’ll generate a column named ‘Pump Time‘ that will utilize the index of our Pandas dataframe. What is the index? That is a column that pandas has generated when we imported our CSV data that starts at 0 and increments each line down the data frame. Frac data is typically in seconds, so let’s convert this to minutes for visualization.

Next, we use the Matplotlib library to build our plot. Our Pandas dataframe has some plotting functions built in that work with the Matplotlib library. The created ‘Pump Time’ column will be the ‘X‘ axis. The ‘Y‘ axis is set to our pressure while pumping. Coloring and settings are just preferences that can be changed to your preference.

import matplotlib.pyplot as plt
...

# Create a Pump Time column, data in seconds so convert to minutes
stageSeven['Pump Time'] = stageSeven.index/60

...

# Add data to plot, get initial view
fig, ax = plt.subplots()

# Create a plot of stage 7's wellhead pressure
stageSeven.plot(kind='line',x='Pump Time', y='Wellside Pressure', 
                label='Pressure - Stg 7', color='#FF0000', ax=ax, linestyle='-')

...

plt.show()

So at this point, we have a chart showing the pressure trend throughout the stage. Nothing special, but we have the building blocks to really make things move forward now.

Great, now let’s add pump rate to the chart so we can understand a little more about the pressure trends (or lack thereof).


Chart Customization

Okay, that is a poor visual. The code below shows how we added our pump rate to the chart. Our priority is to move the pump rate to a second Y axis. We want our pump rate data to share an ‘X‘ axis, so we call ‘ax.twinx()‘ to generate our new Y axis. Variable ‘ax2‘ is referenced when plotting the ‘Slurry Rate’ data. I added some code to suppress the legends on our chart. With us creating different axis to plot with, it will get messy and require some clean up later.

import pandas as pd
import matplotlib.pyplot as plt

# Load our CSV file into a pandas dataframe
stageSeven = pd.read_csv('Stage 7.csv')

# Create a minutes column
stageSeven['Pump Time'] = stageSeven.index/60

# Add data to plot, get initial view
fig, ax = plt.subplots()

# Create a secondary Y axis for pump rate
ax2 = ax.twinx()


stageSeven.plot(kind='line',x='Pump Time', y='Wellside Pressure', 
                label='Pressure - Stg 7', color='#FF0000', ax=ax , linestyle='-')
stageSeven.plot(kind='line',x='Pump Time', y='Slurry Rate', 
                label='Rate - Stg 7',color='#32A1FE', ax=ax2)

# Clean up plot settings
ax.get_legend().remove()
ax2.get_legend().remove()


# Show Chart
plt.show()

Almost there! Let’s add our proppant concentration. You’ll notice some code below to make sure our different ‘Y’ axis are not overlapping.

import pandas as pd
import matplotlib.pyplot as plt

# Load our CSV file into a pandas dataframe
stageSeven = pd.read_csv('Stage 7.csv')

# Create a minutes column
stageSeven['Pump Time'] = stageSeven.index/60

# Add data to plot, get initial view
fig, ax = plt.subplots()

# Create a secondary Y axis for pump rate, and a third Y for proppant
ax2 = ax.twinx() #use ax2 for pump rate
ax3 = ax.twinx() #use ax3 for proppant

stageSeven.plot(kind='line',x='Pump Time', y='Wellside Pressure', 
                label='Pressure - Stg 7', color='#FF0000', ax=ax , linestyle='-')
stageSeven.plot(kind='line',x='Pump Time', y='Slurry Rate', 
                label='Rate - Stg 7',color='#32A1FE', ax=ax2)
stageSeven.plot(kind='line',x='Pump Time', y='Measured Density', label='Proppant - Stg 7',color='#DFD300', ax=ax3)


# Clean up plot settings
ax.get_legend().remove()
ax2.get_legend().remove()
ax3.get_legend().remove()

# Code to pull the Y axis labels proppant to the right of pump rate
ax3.spines['right'].set_position(('outward', 50))


# Show Chart
plt.show()

Cleaning the Presentation

We are getting close to giving this CSV back to data van quality. In the code below, I am going to do a lot of upgrading to the visual.

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator)

# Load our CSV file into a pandas dataframe
stageSeven = pd.read_csv('Stage 7.csv')

# Create a minutes column
stageSeven['Pump Time'] = stageSeven.index/60

# Add data to plot, get initial view
fig, ax = plt.subplots()

# Create a secondary Y axis for pump rate, and a third Y for proppant
ax2 = ax.twinx() #use ax2 for pump rate
ax3 = ax.twinx() #use ax3 for proppant

# Set Axis min and max
ax.set_ylim(0,12000)
ax2.set_ylim(0,120)
ax3.set_ylim(0,12)


stageSeven.plot(kind='line',x='Pump Time', y='Wellside Pressure', 
                label='Pressure - Stg 7', color='#FF0000', ax=ax , linestyle='-')
stageSeven.plot(kind='line',x='Pump Time', y='Slurry Rate', 
                label='Rate - Stg 7',color='#32A1FE', ax=ax2)
stageSeven.plot(kind='line',x='Pump Time', y='Measured Density', label='Proppant - Stg 7',color='#DFD300', ax=ax3)

# Label the axis
ax.set_xlabel('Pump Time (min)', fontsize=12)
ax.set_ylabel('Pressure (psi)', fontsize=12, color='#FF0000')
ax2.set_ylabel('Rate (bpm)', fontsize=12, color='#32A1FE')
ax3.set_ylabel('Proppant (ppg)', fontsize=12, color='#DFD300')


# Clean up plot settings
ax.get_legend().remove()
ax2.get_legend().remove()
ax3.get_legend().remove()

# Code to pull the Y axis labels proppant to the right of pump rate
ax3.spines['right'].set_position(('outward', 50))

# Add major gridlines to plot
ax.grid(which='major', axis='both', linestyle='--')

plt.title('ShaleInsights EFT 1H - Stage 7')

plt.tight_layout()

# Show Chart
plt.show()
plt.figure(figsize=(2000,2000))
fig.savefig('ShaleInsights EFT 1H - Stage 7', dpi=500)

Viewing Multiple Stages

That covers some simple techniques necessary for manipulating stimulation data. As a bonus, let’s analyze the variation between two stages and try to visualize the impact of some change that was made. Code is below, followed by the final chart output.

"""
Created on Wed Oct  7 20:14:32 2020

@author: @FracLost
"""

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter, AutoMinorLocator)

# Load our CSV file into a pandas dataframe
stageSeven = pd.read_csv('Stage 7.csv')
stageEight = pd.read_csv('Stage 8.csv')

# Create a minutes column
stageSeven['Pump Time'] = stageSeven.index/60
stageEight['Pump Time'] = stageEight.index/60

#stageEight['Pump Time'] = stageEight['Pump Time']-4

# Add data to plot, get initial view
fig, ax = plt.subplots()

# Create a secondary Y axis for pump rate, and a third Y for proppant
ax2 = ax.twinx() #use ax2 for pump rate
ax3 = ax.twinx() #use ax3 for proppant

# Set Axis min and max
ax.set_ylim(0,12000)
ax2.set_ylim(0,120)
ax3.set_ylim(0,12)

# Stage 7 Plotting
stageSeven.plot(kind='line',x='Pump Time', y='Wellside Pressure', 
                label='Pressure - Stg 7', color='#FF0000', ax=ax , linestyle='-', alpha=0.5)
stageSeven.plot(kind='line',x='Pump Time', y='Slurry Rate', 
                label='Rate - Stg 7',color='#32A1FE', ax=ax2, alpha=0.5)
stageSeven.plot(kind='line',x='Pump Time', y='Measured Density', label='Proppant - Stg 7',color='#DFD300', ax=ax3, alpha=0.5)

# Stage 8 Plotting
stageEight.plot(kind='line',x='Pump Time', y='Wellside Pressure', 
                label='Pressure - Stg 8', color='#FF0000', ax=ax , linestyle='-')
stageEight.plot(kind='line',x='Pump Time', y='Slurry Rate', 
                label='Rate - Stg 8',color='#32A1FE', ax=ax2)
stageEight.plot(kind='line',x='Pump Time', y='Measured Density', label='Proppant - Stg 8',color='#DFD300', ax=ax3)


# Label the axis
ax.set_xlabel('Pump Time (min)', fontsize=12)
ax.set_ylabel('Pressure (psi)', fontsize=12, color='#FF0000')
ax2.set_ylabel('Rate (bpm)', fontsize=12, color='#32A1FE')
ax3.set_ylabel('Proppant (ppg)', fontsize=12, color='#DFD300')


# Clean up plot settings
ax.get_legend().remove()
ax2.get_legend().remove()
ax3.get_legend().remove()

# Code to pull the Y axis labels proppant to the right of pump rate
ax3.spines['right'].set_position(('outward', 50))

# Add major gridlines to plot
ax.grid(which='major', axis='both', linestyle='--')

plt.title('ShaleInsights EFT 1H - Stage 7 & Stage 8')

plt.tight_layout()

# Show Chart
plt.show()
plt.figure(figsize=(2000,2000))
fig.savefig('ShaleInsights EFT 1H - Stage 7 & Stage 8', dpi=500)

Summary

From the image above, we can see that the company representative pumping stage 8 made some slight adjustments compared to stage 7. The treating pressure is slightly higher on stage 8, which may have been due to an alteration in the perforating scheme or a change in the fluid system. The pad pumped on stage 7 was shorter than stage 8, leading to stage 7 taking slightly less time to get all the dirt downhole.

In conclusion, this should give you the confidence and core techniques to manipulate the data you have sitting that hard drive collecting dust. This is just the beginning of what can be done. I’ll take this a step further in a later installment and make an interactive version with a full user interface.

Python tutorials can be found here.

And follow our blog while you’re at it.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: