7.3. Inset of Elastic Region#
This is the second section on how to plot stress strain curves with Python and Matplotlib. In the previous section we built a stress strain curve from the data in two .xls data files. The plot built in the previous section included two lines, axes labels, a title and legend. The data in the plot came from two .xls excel files and was from a tensile test of two metal samples.
The code below builds the plot in the previous section.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
steel_df = pd.read_excel("Al60601_raw_data.xls")
al_df = pd.read_excel("Steel1018_raw_data.xls")
strain_al = al_df['CH5']*0.01
d_al = 0.506
stress_al = (al_df['FORCE']*0.001)/(np.pi*((d_al/2)**2))
strain_steel = steel_df['CH5']*0.01
d_steel = 0.506
stress_steel = (steel_df['FORCE']*0.001)/(np.pi*((d_steel/2)**2))
plt.plot(strain_al,stress_al,strain_steel,stress_steel)
plt.xlabel('strain (in/in)')
plt.ylabel('stress (ksi)')
plt.title('Stress Strain Curve of Aluminum 6061 and Steel 1045 in tension')
plt.legend(['Aluminum 6061','Steel 1045'])
plt.show()
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
In this section, we are going to add an inset curve to the plot that shows the linear elastic region. An inset curve is a small plot that is placed within a plot that shows a zoomed-in view of the larger plot. On a stress-strain cuve, an inset curve is used to zoom-in on the linear elastic region on the plot.
To build our inset curve, we will use Python and Matplotlib’s object-oriented interface. The plot above was constructed using the Matplotlib’s pyplot interface. For a simple plot, the pyplot interface above is sufficient.
But our plot with an inset curve is more complicated than the plot above. Matplotlib’s object-oriented interface allows us to access individual components of the plot, like axes, and set specific attributes on these components. This added versitility means we can include an inset curve within another plot.
To build the plot with an inset curve, first we need to import a couple modules: NumPy, Pandas, and Matplotlib. These three modules have common import aliases np
, pd
, and plt
. The line %matplotlib inline
is a Jupyter notebook magic command that will show plots directly in a Jupyter notebook. If you are coding your inset curve in a .py file, leave %matplotlib inline
out, as it is not valid Python code.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
Next we need to bring in the data from two external files into variables in our script. The two external files that contain the data we are going to plot are linked below:
If you are following along and building an inset curve yourself, make sure to download the .xls data files and place these data files in the same directory as you Jupyter notebook or Python script.
A conveniant Jupyter notebook magic command, %ls
, lists the contents of the current directory (the directory where the notebook is saved). Make sure you can see the two .xls data files in this directory.
%ls
ABS_HIPS_plot_with_error_bars.png
Al60601_raw_data.xls
Steel1018_raw_data.xls
bar_plot_with_error_bars.ipynb
calculate-yield-strength-programmatically.ipynb
images/
mechanical-properties-from-stress-strain-curves.ipynb
mechanical-properties-intro.md
plotting-stress-strain-curves.ipynb
stress-strain_curve.png
stress_strain_curve_with_inset.png
stress_strain_curve_with_inset_elastic_region.ipynb
We can see the two data files Al60601_raw_data.xls
and Steel1018_raw_data.xls
in the same folder as our Jupyter notebook stress_strain_curve_with_inset_elastic_region.ipynb
Next, we will read in the two .xls data files using Pandas pd.read_excel()
function. The result is two Pandas dataframes steel_df
and al_df
.
steel_df = pd.read_excel("Al60601_raw_data.xls")
al_df = pd.read_excel("Steel1018_raw_data.xls")
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero
We can use Pandas df.head()
method to view the first five rows of each dataframe.
steel_df.head()
TESTNUM | POINTNUM | TIME | POSIT | FORCE | EXT | CH5 | CH6 | CH7 | CH8 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 542 | 1 | 8.470 | 0.02256 | 201.146011 | -0.001444 | 0.007552 | NaN | NaN | NaN |
1 | 542 | 2 | 8.632 | 0.02330 | 206.599442 | 0.000302 | 0.007552 | NaN | NaN | NaN |
2 | 542 | 3 | 10.027 | 0.02846 | 287.512573 | 0.003044 | 0.018898 | NaN | NaN | NaN |
3 | 542 | 4 | 11.031 | 0.03232 | 365.380981 | 0.009881 | 0.022061 | NaN | NaN | NaN |
4 | 542 | 5 | 11.928 | 0.03616 | 447.813965 | 0.014085 | 0.033652 | NaN | NaN | NaN |
al_df.head()
TESTNUM | POINTNUM | TIME | POSIT | FORCE | EXT | CH5 | CH6 | CH7 | CH8 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 523 | 1 | 6.189 | 0.07302 | 202.924728 | 0.000402 | -0.028272 | NaN | NaN | NaN |
1 | 523 | 2 | 6.549 | 0.07396 | 205.714890 | -0.000238 | -0.034549 | NaN | NaN | NaN |
2 | 523 | 3 | 7.148 | 0.07624 | 217.763336 | -0.000713 | -0.030140 | NaN | NaN | NaN |
3 | 523 | 4 | 9.146 | 0.08438 | 316.306122 | 0.002377 | -0.025968 | NaN | NaN | NaN |
4 | 523 | 5 | 10.041 | 0.08822 | 417.003357 | 0.003089 | -0.024100 | NaN | NaN | NaN |
We see a couple of columns in each dataframe. The columns we are interest in are below:
FORCE Force measurements from the load cell in pounds (lb)
EXT Extension measurements from the mechanical extensometer in percent (%), strain in percent
CH5 Extension readings from the laser extensometer in percent (%), strain in percent
We will use these columns from the dataframes in the following ways
FORCE will be converted to stress using the cross-sectional area of our test samples
EXT (mechanical exstensometer readings) will be converted into strain on our inset cuve
CH5 (laser extensometer readings) will be converted into strain on the overall, large stress strain curve
strain_al_plastic = al_df['CH5']*0.01
strain_al_elastic = al_df['EXT']*0.01
d_al = 0.506
stress_al = (al_df['FORCE']*0.001)/(np.pi*((d_al/2)**2))
strain_steel_plastic = steel_df['CH5']*0.01
strain_steel_elastic = steel_df['EXT']*0.01
d_steel = 0.506
stress_steel = (steel_df['FORCE']*0.001)/(np.pi*((d_steel/2)**2))
Now that we have the data in 6 pandas series, we can build a simple plot. We’ll use Matplotlib’s object-oriented interface to create to objects, a figure object called fig
and an axes object ax1
. Then we can run the .plot()
method on our ax1
object and pass in two sets of series. The command plt.show()
shows the plot.
fig, ax1 = plt.subplots()
ax1.plot(strain_al_plastic,stress_al,strain_steel_plastic,stress_steel)
plt.show()
We see a plot that contains two lines.
Next let’s use Matplotlib’s object-oriented interface to add axis labels and titles. Below is a chart that relates how to use Matplotlib’s plt
approach, compared to the object-oriented approach that we’ll use.
plot component |
|
object-oriented approach |
---|---|---|
x-axis label |
|
|
y-axis label |
|
|
title |
|
|
legend |
|
|
fig, ax1 = plt.subplots()
fig.set_size_inches([9,9])
ax1.plot(strain_al_plastic,stress_al,strain_steel_plastic,stress_steel)
ax1.legend(['Al6061','Steel1045'])
ax1.set_xlabel('Strain (in/in)')
ax1.set_ylabel('Stress (ksi)')
ax1.set_title('Stress Strain Curve of Al6061 and Steel1045 in Tension')
plt.show()
Next, let’s add the inset curve. Our inset curve is a zoomed-in view of the linear elastic region. We’ll use Matplotlib’s ax.add_axes([ ])
method. This method outputs a new axis object ax2
. ax2
will be the axes that we plot the inset curve on. We can set attributes like .set_xlabel()
on our ax2
object to add labels to the axis, add a title, and limit the x and y axis.
fig, ax1 = plt.subplots()
fig.set_size_inches([9,9])
ax1.plot(strain_al_plastic,stress_al,strain_steel_plastic,stress_steel)
ax1.legend(['Al6061','Steel1045'])
ax1.set_xlabel('Strain (in/in)')
ax1.set_ylabel('Stress (ksi)')
ax1.set_title('Stress Strain Curve of Al6061 and Steel1045 in Tension \n with inset curve of elastic region')
left, bottom, width, height = [0.35, 0.2, 0.25, 0.25]
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(strain_al_elastic,stress_al,strain_steel_elastic, stress_steel)
ax2.set_xlabel('Strain (in/in)')
ax2.set_ylabel('Stress (ksi)')
ax2.set_title('Inset of Elastic Region')
ax2.set_xlim([0,0.006])
ax2.set_ylim([0,75])
fig.savefig('stress_strain_curve_with_inset.png')
plt.show()
We see a plot that contains an inset curve. The inset curve has two lines, just like the large plot. The inset curve has axis labels and a title. The same colors in the main plot is used in the inset plot.
Summary#
In this section, we plotted a stress strain curve with Python and Matplotlib. We used Matplotlib’s object oriented interface to build the inset curve. Our inset curve was added on top of our main plot.