<jupyter_start><jupyter_text>Plotting Stress-strain curves in reproducible wayThis tutorial will show how to plot 'publication' quality stress strain curves using python. The datasets are in form of excel files, which we assume to be the standard way in which the stress strain curve data is stored. The tutorial will cover basics of python programming language.Moreover, this notebook can be modified to handle large amounts of datafiles of similar format to plot multiple curves at once and have a reproducible plotting style  Why use python for plotting? - Flexible, any special plot feature can be created- Free and open source- calculations are faster and other options for data analysis- reproducibility- Automate repetitive steps*with **jupterhub server** python is easier to use than ever*  Modules in pythonPython has a huge library of codes. These different types of codes can be bound together into modules.When we want to use these set of codes for certain purpose, we **import** them.Once you import some module, you can use the functions/classes etc present in it.To enable use of access, we also rename the modules to the names we want. Following modules are used in this notebook:1. [pandas](https://pandas.pydata.org/)            - For Data analysis and manipulation 2. [numpy](https://numpy.org/)                     - Package for numerical/scientific computing with lots of array based calculations 3. [math](https://docs.python.org/3/library/math.html) - Module for mathematical functions3. [matplotlib](https://matplotlib.org/)           - The most widely used plotting library based on python 4. [os](https://docs.python.org/3/library/os.html) - Library for Operating system related functionality<jupyter_code>import pandas as pd
import numpy as np
import math
import os
import matplotlib as mpl
import matplotlib.pyplot as PyPlot
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Reading in excel fileBased on my excel file, I know that the relevant data is from row 5 (in python it is row 4 as counting starts from 0).And I use only columns A to L.In the function below, we first give the name of the excel file.Then we specify, from which row in the excel file is used to label our data. As row 4 (start counting at 0!!) has the column names, we say header is 4. This is how the file looks here now in form of a **DataFrame**<jupyter_code>df<jupyter_output><empty_output><jupyter_text>Accessing data within a dataframeThe data in the columns of a dataframe can be accessed by calling out the name of the column as shown below<jupyter_code>df['True Strain']<jupyter_output><empty_output><jupyter_text>Plotting<jupyter_code>PyPlot.plot(df['True Strain'],df['True Stress'])<jupyter_output><empty_output><jupyter_text>Looping over filesBut as we want to use the power that python provides, we would like to do everything at once. ***Loop*** give us this power - Looping is basically repeating a set of commands number of timesAlso we need to know something about the datatypes in python: **Lists** and **Dictionaries**  List exampleThis is an example of list. It is denoted by square brackets **[ ]**It is used to store iterable (looping possibilities) items to be called by a single variable.<jupyter_code># empty list
example_list = []

# list of integers
example_list = [1, 2, 3]
# Call list items
example_list[0]<jupyter_output><empty_output><jupyter_text>In the example below, the list has multiple file names which we can loop over (iterable).<jupyter_code>os.listdir('sample_data/')<jupyter_output><empty_output><jupyter_text>Dictionary exampleDictionary is similar to our 'normal' dictionaries. They are denoted by curly brackets **{ }**. Dictionaries can store any kind of data/data structure as values.We have key and value pairs.<jupyter_code>example_dict = {'a':1, 'b': 2}
example_dict = {'a':'Apple', 'b': 'Banana'}
example_dict = {'a':[1,2,3], 'b': [4,5,6]}
# what does one specific key correspond to?
example_dict['a']<jupyter_output><empty_output><jupyter_text>So we will create a dictionary which will reference to the dataframes like we saw beforeWe will create a empty dictionary and then add entries to it<jupyter_code>data_dict = {}
for i in os.listdir('sample_data/'):

data_dict.keys()
data_dict['Data_1.xlsx']<jupyter_output><empty_output><jupyter_text>Finding stress and strain limits in the whole dataset<jupyter_code>max_stress_lim = 0.0
max_strain_lim = 0.0
for expt_data in data_dict.values():
    max_y_lim = #finding maximum stress for a given file
    max_x_lim = #finding maximum strain for a given file
    if max_y_lim > max_stress_lim:
        max_stress_lim = max_y_lim
    if max_x_lim > max_strain_lim:
        max_strain_lim = max_x_lim
max_strain_lim
max_stress_lim<jupyter_output><empty_output><jupyter_text>Rounding off values<jupyter_code>max_strain_lim = round(max_strain_lim * 2.0) / 2.0
max_stress_lim = (round(max_stress_lim/50.0)+2.0)*50.0
max_stress_lim,max_strain_lim<jupyter_output><empty_output><jupyter_text>Plot settings Create a simple plot by looping<jupyter_code>fig, ax = PyPlot.subplots()

for datas in data_dict.values():
    PyPlot.plot(datas['True Strain'],
                datas['True Stress']
                )<jupyter_output><empty_output><jupyter_text>This is a very simple plotNot yet publication ready.Generally we change following things:1. Colors2. Linestyles3. Linewidths4. Labels5. Axes labels6. Axes limits7. Axes ticks (optional)<jupyter_code>set_colors = ['black','red','teal','fuchsia','blue'] # https://matplotlib.org/gallery/color/named_colors.html
linestyle_list = ['solid', 'dashed', 'dashdot', 'dotted']
label_list = [1073,1173,1273,1373]
fig, ax = PyPlot.subplots()
ax.tick_params(which='both',direction="in",top=True,right=True)
ax.minorticks_on()

#for count,i in enumerate(data_dict.keys()):
for datas,line,colors,labels in zip(data_dict.values(),linestyle_list,set_colors,label_list):
    PyPlot.plot(datas['True Strain'],
                datas['True Stress'],
                color=colors,
                linewidth = 2.5,
                linestyle = line,
                label = labels
                )
    PyPlot.xlim(-0.025,max_strain_lim)
    PyPlot.ylim(0.0,max_stress_lim)
    PyPlot.xlabel(r'$\epsilon$(-)',fontsize=18)   # latex based symbols
    PyPlot.ylabel(r'$\sigma$ (MPa)',fontsize=18)
    PyPlot.legend(title=r'$ T (\mathrm{K})$')#,title_fontsize ='large')
        
fig.savefig('multi_stress_strain.png',dpi=600)<jupyter_output><empty_output><jupyter_text>Cutting off dataCan be done automatically but easiest way is manually.We can look at where we want to cut off and give that value<jupyter_code>cut_off_strains = []
data_dict_2 = {}
data_dict_2['Data_1.xlsx'] = data_dict['Data_1.xlsx'].loc[data_dict['Data_1.xlsx']['True Strain'] < 0.88]
PyPlot.plot(data_dict_2['Data_1.xlsx']['True Strain'],data_dict_2['Data_1.xlsx']['True Stress'])<jupyter_output><empty_output><jupyter_text>Automating cut off Idea: See where the derivative drops significantlyFor automation might need smooth dataNeed simpler ideas for python newbies. I dont want to make a complicated code.<jupyter_code>from scipy.signal import savgol_filter
fig,ax1 = PyPlot.subplots()
ax1.plot(data_dict['Data_4.xlsx']['True Strain'],savgol_filter(data_dict['Data_4.xlsx']['True Stress'],31,9,deriv=1))
ax2 = ax1.twinx()
ax2.plot(data_dict['Data_4.xlsx']['True Strain'],data_dict['Data_4.xlsx']['True Stress'])
index_min = np.argmin(savgol_filter(data_dict['Data_1.xlsx']['True Stress'],71,9,deriv=1))
data_dict['Data_1.xlsx']['True Strain'][index_min]
math.floor(0.8953057035808059*50.0)/50.0
data_dict['Data_4.xlsx'].loc[data_dict['Data_4.xlsx']['True Strain'] < 0.88]
new_data_dict = {}
for datas,name in zip(data_dict.values(),data_dict.keys()):
    index_min = np.argmin(savgol_filter(datas['True Stress'],31,9,deriv=1))
    cut_off_value = datas['True Strain'][index_min]
    rounded_cut_off = math.floor(cut_off_value*50.0)/50.0
    new_data_dict[name] = datas.loc[datas['True Strain'] < rounded_cut_off]
new_data_dict['Data_1.xlsx']
fig, ax = PyPlot.subplots()
ax.tick_params(which='both',direction="in",top=True,right=True)
ax.minorticks_on()

#for count,i in enumerate(data_dict.keys()):
for datas,line,colors,labels in zip(new_data_dict.values(),linestyle_list,set_colors,label_list):
    PyPlot.plot(datas['True Strain'],
                datas['True Stress'],
                color=colors,
                linewidth = 2.5,
                linestyle = line,
                label = labels
                )
    PyPlot.xlim(-0.025,max_strain_lim)
    PyPlot.ylim(0.0,max_stress_lim)
    PyPlot.xlabel(r'$\epsilon$(-)',fontsize=18)   # latex based symbols
    PyPlot.ylabel(r'$\sigma$ (MPa)',fontsize=18)
    PyPlot.legend(title=r'$ T (\mathrm{K})$')#,title_fontsize ='large')
        
fig.savefig('multi_stress_strain_cut_off.png',dpi=600)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11069819819819819, 'fraction_numerical': 0.018581081081081082, 'mean_word_length': 5.008795669824087, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 59, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '642634', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 3030, 'n_tokens_neox': 2806, 'n_words': 827, 'path': 'exercise_notebooks/Plot_stress_strain_curves.ipynb', 'repo_name': 'eisenforschung/workshop-experimental-data-visualisation', 'size': '8880'}