How to create a path and extract data from it using python? - python

I am performing a simulation in Abaqus that consists of the impact of two plates. Imagine that the simulation has 100 frames, what I want is to extract data along a path for a specific frame. I wrote this Python script to extract the velocity and mises data from all the nodes for all frames (the txt file is gigantic), but I want to do it for just a set at a given frame. Does anyone know how to create a node set or path, and then extract the data along this set or path for a certain frame?
Script to export data from abaqus:
import time
import numpy as np
from numpy import savetxt
import math
from odbAccess import *
from textRepr import *
import os, sys
#import matplotlib.pyplot
start_time = time.time()
path = (os.getcwd())
odbName = '%s/Job-1.odb'%path
odb = openOdb(odbName, readOnly=True)
myAssembly = odb.rootAssembly.instances['FIXED-1']
newpath = 'results'
if not os.path.exists(newpath):
os.makedirs(newpath)
steps1 = odb.steps['Step-1'].frames
currentframe1 = []
for c_elem in range(len(steps1)):
currentframe1 = steps1[c_elem]
mises = []
velocity = []
strain = []
displacement = []
fieldvalues_mises = currentframe1.fieldOutputs['S']
fieldvalues_velocity = currentframe1.fieldOutputs['V']
fieldvalues_displacement = currentframe1.fieldOutputs['U']
fieldvalues_strain = currentframe1.fieldOutputs['LE']
vel_set = fieldvalues_velocity.values
disp_set = fieldvalues_displacement.values
mises_set = fieldvalues_mises.values
strain_set = fieldvalues_strain.values
for v in vel_set:
velocity.append(v.data)
for s in strain_set:
strain.append(s.data)
for m in mises_set:
mises.append(m.data)
for d in disp_set:
displacement.append(d.data)
# Vector of frames
vector_frame = c_elem*[1]
with open('velocityFile.txt', 'w') as f:
for i in range(1,len(vector_frame)+1):
f.write('\n\n')
for j in velocity:
f.write(str(j) + 3*' ')
with open('misesFile.txt', 'w') as f:
for i in range(1,len(vector_frame)+1):
f.write('\n\n')
for j in mises:
f.write(str(j) + 3*' ')

Did you open the odb as editable? The default is read only and you CANNOT save something in it, so your line won't be there. This is why abaqus will always tell you that local outputs are only stored in the current session.
Also cathing up on your code snippet, you cannot simply use the name but have to create set in the odb e.g.
odb.rootAssembly.nodeSets['LINE_1']
and use this set in region.
The set has to be present in the assembly.

Yes! Open the odb as editable, create a path of interest and save it in the odb. Use the script to read the variables of interest using the created path. Have a look at Viewing results along a path in the documentation for path creation and obtaining xy results.

Related

Opening files from directory in specific order

I have a folder that contains around 500 images that I am rotating at a random angle from 0 to 360. The files are named 00i.jpeg where i = 0 then i = 1. For example I have an image named 009.jpeg and one named 0052.jpeg and another one 00333.jpeg. My code below works as is does rotate the image, but how the files are being read through is not stepping correctly.
I would think I would need some sort of stepping code chunk that starts at 0 and adds one each time, but I'm not sure where I would put that. os.listdir doesn't allow me to do that because (from my understanding) it just lists the files out. I tried using os.walk but I cannot use cv2.imread. I receive a SystemError: <built-in function imread> returned NULL without setting an error error.
Any suggestions?
import cv2
import imutils
from random import randrange
import os
os.chdir("C:\\Users\\name\\Desktop\\training\\JPEG")
j = 0
for infile in os.listdir("C:\\Users\\name\\Desktop\\training\\JPEG"):
filename = 'testing' + str(j) + '.jpeg'
i = randrange(360)
image = cv2.imread(infile)
rotation_output = imutils.rotate_bound(image, angle=i)
os.chdir("C:\\Users\\name\\Desktop\\rotate_test")
cv2.imwrite("C:\\Users\\name\\Desktop\\rotate_test\\" + filename, rotation_output)
os.chdir("C:\\Users\\name\\Desktop\\training\\JPEG")
j = j + 1
print(infile)
000.jpeg
001.jpeg
0010.jpeg
00100.jpeg
...
Needs to be:
print(infile)
000.jpeg
001.jpeg
002.jpeg
003.jpeg
...
Get a list of files first, then use sort with key where the key is an integer version of the file name without extension.
files = os.listdir("C:\\Users\\name\\Desktop\\training\\JPEG")
files.sort(key=lambda x:int(x.split('.')[0]))
for infile in files:
...
Practical example:
files = ['003.jpeg','000.jpeg','001.jpeg','0010.jpeg','00100.jpeg','002.jpeg']
files.sort(key=lambda x:int(x.split('.')[0]))
print(files)
Output
['000.jpeg', '001.jpeg', '002.jpeg', '003.jpeg', '0010.jpeg', '00100.jpeg']

How to append "_projected.shp" at the end of each dataset name

I have a code that projects a number of shapefiles in a folder to another coordinate system and the projected shapefiles are placed in another folder. For the projected shapefiles, I want to append "_projected" at the end each shapefile name.
What I have so far works for the projection and setting the output files into a specific folder, but the new output files are not showing the "_projected" at the end.
Here is my code
import arcpy
import os
arcpy.env.workspace = "inputdatafolder"
arcpy.env.overwriteOutput = True
outWorkspace = "outputdatafolder"
for infc in arcpy.ListFeatureClasses():
dsc = arcpy.Describe(infc)
if dsc.spatialReference.Name == "Unknown":
print ("skipped this fc due to undefined coordinate system: "+ infc)
else:
outfc = os.path.join(outWorkspace, infc)
outCS = arcpy.SpatialReference('NAD 1983 UTM Zone 10N')
arcpy.Project_management(infc, outfc, outCS)
infc = infc.replace(".shp","_projected.shp")
Since the code works, I am not getting any errors. The file name just isn't replaced with the ending I want it to.
Your code is replacing the text of the filepath of infc, but not actually renaming the file.
Furthermore, outfc is the path to the new projected shapefile you are creating, while infc is the path to the original file. Don't you want outfc to have the "_projected.shp"suffix?
The code below changes the text of the output file path to include "_projected.shp" before calling arcpy.Project_management to create the new file.
import arcpy
import os
arcpy.env.workspace = "inputdatafolder"
arcpy.env.overwriteOutput = True
outWorkspace = "outputdatafolder"
for infc in arcpy.ListFeatureClasses():
dsc = arcpy.Describe(infc)
if dsc.spatialReference.Name == "Unknown":
print ("skipped this fc due to undefined coordinate system: "+ infc)
else:
outfc = os.path.join(outWorkspace, infc).replace(".shp","_projected.shp")
outCS = arcpy.SpatialReference('NAD 1983 UTM Zone 10N')
arcpy.Project_management(infc, outfc, outCS)
I'm also not sure if you're using Describe correctly. You may need to use infc.name when constructing the file paths.

Iteratively open image with increasing ID number as a file name in pyhon

I've got an image database with a set of images named [frame01.png, frame02.png, ..., frameN.png].
My directory path is ./img, and iteratively I'd like to read one by one, do some image processing until reaching the last one. Since I'm not familiar with strings concatenation in python, what's the easiest way to do it?
file_names = os.listdir('path_to_folder/')
should give you a list of all you files.
To read them you can have:
for file_name in file_names:
read_and_process_image('path_to_folder/' + file_name)
Then inside read_and_process_image:
import matplotlib.image
def read_and_process_image(path):
read_img = matplotlib.image.imread(path) # or whatever you use to read the image
# process read_img
Alternatively, you could have:
import glob
for image_path in glob.glob("path_to_your_image*.png"):
image = matplotlib.image.imread(image_path) # or whatever you use to read the image
# process your image
If you are just looking for a quick way to create the list with this particular names:
[ 'frame' + "%02d" % (i,) + '.png' for i in range(1, MAX_NUM)]
If your last image is 20 then replace MAX_NUM with 20 + 1 applies for any other number x, x + 1.
How/what you use to read the files depends on you. You can use matplotlib.image as in the examples or whatever works for you.

Reading images while maintaining folder structure

I have to write a matlab script in python as apparently what I want to achieve is done much more efficiently in Python.
So the first task is to read all images into python using opencv while maintaining folder structure. For example if the parent folder has 50 sub folders and each sub folder has 10 images then this is how the images variable should look like in python, very much like a cell in matlab. I read that python lists can perform this cell like behaviour without importing anything, so thats good I guess.
For example, below is how I coded it in Matlab:
path = '/home/university/Matlab/att_faces';
subjects = dir(path);
subjects = subjects(~strncmpi('.', {subjects.name}, 1)); %remove the '.' and '..' subfolders
img = cell(numel(subjects),1); %initialize the cell equal to number of subjects
for i = 1: numel(subjects)
path_now = fullfile(path, subjects(i).name);
contents = dir([path_now, '/*.pgm']);
for j = 1: numel(contents)
img{i}{j} = imread(fullfile(path_now,contents(j).name));
disp([i,j]);
end
end
The above img will have 50 cells and each cell will have stored 10 images. img{1} will be all images belonging to subject 1 and so on.
Im trying to replicate this in python but am failing, this is what I have I got so far:
import cv2
import os
import glob
path = '/home/university/Matlab/att_faces'
sub_f = os.listdir(path)
images = []
for n in sub_f:
path_now = os.path.join(path, sub_f[n], '*.pgm')
images[n] = [cv2.imread(file) for file in glob.glob(path_now)]
Its not exactly what I am looking for, some help would be appreciated. Please ignore silly mistakes as it is my first day writing in python.
Thanks
edit: directory structure:
The first problem is that n isn't a number or index, it is a string containing the path name. To get the index, you can use enumerate, which gives index, value pairs.
Second, unlike in MATLAB you can't assign to indexes that don't exist. You need to pre-allocate your image array or, better yet, append to it.
Third, it is better not to use the variable file since in python 2 it is a built-in data type so it can confuse people.
So with preallocating, this should work:
images = [None]*len(sub_f)
for n, cursub in enumerate(sub_f):
path_now = os.path.join(path, cursub, '*.pgm')
images[n] = [cv2.imread(fname) for fname in glob.glob(path_now)]
Using append, this should work:
for cursub in sub_f
path_now = os.path.join(path, cursub, '*.pgm')
images.append([cv2.imread(fname) for fname in glob.glob(path_now)])
That being said, there is an easier way to do this. You can use the pathlib module to simplify this.
So something like this should work:
from pathlib import Path
mypath = Path('/home/university/Matlab/att_faces')
images = []
for subdir in mypath.iterdir():
images.append([cv2.imread(str(curfile)) for curfile in subdir.glob('*.pgm')])
This loops over the subdirectories, then globs each one.
This can even be done in a nested list comprehension:
images = [[cv2.imread(str(curfile)) for curfile in subdir.glob('*.pgm')]
for subdir in mypath.iterdir()]
It should be the following:
import os
path = '/home/university/Matlab/att_faces'
sub_f = os.listdir(path)
print(sub_f) #--- this will print all the files present in this directory ---
#--- this a list to which you will append all the images ---
images = []
#--- iterate through every file in the directory and read those files that end with .pgm format ---
#--- after reading it append it to the list ---
for n in sub_f:
if n.endswith('.pgm'):
path_now = os.path.join(path, n)
print(path_now)
images.append(cv2.imread(path_now, 1))
import cv2
import os
import glob
path = '/home/university/Matlab/att_faces'
sub_f = os.listdir(path)
images = []
#read the images
for folder in sub_f:
path_now = os.path.join(path, folder, '*.pgm')
images.append([cv2.imread(file) for file in glob.glob(path_now)])
#display the images
for folder in images:
for image in folder:
cv2.imshow('image',image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Error recognizing parameters for a spatial join using ArcPy

I'm trying to iterate a spatial join through a folder - then iterate a second spatial join through the outputs of the first.
This is my initial script:
import arcpy, os, sys, glob
'''This script loops a spatial join through all the feature classes
in the input folder, then performs a second spatial join on the output
files'''
#set local variables
input = "C:\\Users\\Ryck\\Test\\test_Input"
boundary = "C:\\Users\\Ryck\\Test\\area_Input\\boundary_Test.shp"
admin = "C:\\Users\\Ryck\\Test\\area_Input\\admi_Boundary_Test.shp"
outloc = "C:\\Users\\Ryck\\Test\\join_02"
#overwrite any files with the same name
arcpy.env.overwriteOutput = True
#perform spatial joins
for fc in input:
outfile = outloc + fc
join1 = [arcpy.SpatialJoin_analysis(fc,boundary,outfile) for fc in
input]
for fc in join1:
arcpy.SpatialJoin_analysis(fc,admin,outfile)
I keep receiving Error00732: Target Features: Dataset C does not exist or is not supported.
I'm sure this is a simple error, but none of the solutions that have previously been recommended to solve this error allow me to still output my results to their own folder.
Thanks in advance for any suggestions
You appear to be trying to loop through a given directory, performing the spatial join on (shapefiles?) contained therein.
However, this syntax is a problem:
input = "C:\\Users\\Ryck\\Test\\test_Input"
for fc in input:
# do things to fc
In this case, the for loop is iterating over a string. So each time through the loop, it takes one character at a time: first C, then :, then \... and of course the arcpy function fails with this input, because it expects a file path, not a character. Hence the error: Target Features: Dataset C does not exist...
To instead loop through files in your input directory, you need a couple extra steps. Build a list of files, and then iterate through that list.
arcpy.env.workspace = input # sets "workspace" to input directory, for next tool
shp_list = arcpy.ListFiles("*.shp") # list of all shapefiles in workspace
for fc in shp_list:
# do things to fc
(Ref. this answer on GIS.SE.)
After working through some kinks, and thanks to the advice of #erica, I decided to abandon my original concept of a nested for loop, and approach more simply. I'm still working on a GUI that will create system arguments that can be assigned to the variables and then used as parameters for the spatial joins, but for now, this is the solution I've worked out.
import arcpy
input = "C:\\Users\\Ryck\\Test\\test_Input\\"
boundary = "C:\\Users\\Ryck\\Test\\area_Input\\boundary_Test.shp"
outloc = "C:\\Users\\ryck\\Test\\join_01"
admin = "C:\\Users\\Ryck\\Test\\area_Input\\admin_boundary_Test.shp"
outloc1 = "C:\\Users\\Ryck\\Test\\join_02"
arcpy.env.workspace = input
arcpy.env.overwriteOutput = True
shp_list = arcpy.ListFeatureClasses()
print shp_list
for fc in shp_list:
join1 =
arcpy.SpatialJoin_analysis(fc,boundary,"C:\\Users\\ryck\\Test\\join_01\\" +
fc)
arcpy.env.workspace = outloc
fc_list = arcpy.ListFeatureClasses()
print fc_list
for fc in fc_list:
arcpy.SpatialJoin_analysis(fc,admin,"C:\\Users\\ryck\\Test\\join_02\\" +
fc)
Setting multiple environments and using the actual paths feels clunky, but it works for me at this point.

Categories

Resources