For loop inside an array? - python

The snippet below is supposed to take in image labels(directory consists of respective labels as file names) in the given directory and plot the image using a subplot.
import os
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
training_hor_dir='./horse-or-human/horses'
training_hum_dir='./horse-or-human/humans'
nrows=4
ncols=4
pic_index=0
fig=plt.gcf()
fig.set_size_inches(ncols*4,nrows*4)
pic_index+=8
next_horse_pic=[os.path.join(training_hor_dir,fname)
for fname in training_hor_labels[pic_index-8:pic_index]]
Can someone please walk me through how the following for loop work? What's the core concept behind such a snippet(join statement followed by for loop inside an array ? I can't get my head around it)?
Also, Is it possible to add in furthermore statements after for loop? If so, how? and if not, why?
And how to print fname inside for-loop?
Any help is appreciated. Thanks in advance.

It's called a comprehension: it's a clever way of creating new data from data you already have. Generally it works like this:
newList = [oldValue * 2 for oldValue in oldList]
Where oldValue * 2 can be replaced with whatever operation you want.
There's lots of other things you can do with comprehensions - too much to list here. Dictionaries, nested comprehensions, and so on. Here's an article to get started.
As for printing (or executing any commands for that matter) technically you can just throw away the new value, like so:
uselessList = [print(item) for item in oldList]
But then the new uselessList would just be loads of Nones. What I'd do is just use another for loop and print the items out the old fashioned way.

Related

I have a list of images "Image1, Image2, Image3...". Is it possible to use for loop to add all of them to a list?

So I have 20 images and I want to put them to a list. But I only know how to do it by appending them one by one which wastes a lot of space. I did try for loop, but I do not know how to make it work.
This is what I want to do, but by using a loop:
list = []
list.append(image1)
list.append(image2)
...
list.append(image20)
What I have tried:
for i in range 20
a = str(i)
list.append(image.join(a))
"image is not defined" is the obvious error I get and I understand what is causing it. The "image" is not defined and I am typing it acting as it should be a variable. Is it somehow possible to change the variable "image" into a string, add str(i) onto it, and then change it back to a variable that includes the number? After which I could input it to the append function.
You can simply do that using glob by filtering image extensions from folder itself.
import glob
img_list = []
for img in glob.glob("Path/to/dir/*.jpg"): #If extension of image is .jpg
img_list.append(img)
I didn't understand if you want to include images or image names, I believe this solution can help you in any of the cases:
list = []
for i in range (20):
list.append(image+"{}".format(i))
print(list)
I found a solution on how to do this this way, even though #Bhargav gave a much more practical solution. Posting this in case it helps someone else in some way. Using eval()
list = []
for i in range (1,20)
list.append(eval("image" + str(i)))

variable dataframe name - loop works by itself, but not inside of function

I have dataframes that follow name syntax of 'df#' and I would like to be able to loop through these dataframes in a function. In the code below, if function "testing" is removed, the loop works as expected. When I add the function, it gets stuck on the "test" variable with keyerror = "iris1".
import statistics
iris1 = sns.load_dataset('iris')
iris2 = sns.load_dataset('iris')
def testing():
rows = []
for i in range(2):
test=vars()['iris'+str(i+1)]
rows.append([
statistics.mean(test['sepal_length']),
statistics.mean(test['sepal_width'])
])
testing()
The reason this will be valuable is because I am subsetting my dataframe df multiple times to create quick visualizations. So in Jupyter, I have one cell where I create visualizations off of df1,df2,df3. In the next cell, I overwrite df1,df2,df3 based on different subsetting rules. This is advantageous because I can quickly do this by calling a function each time, so the code stays quite uniform.
Store the datasets in a dictionary and pass that to the function.
import statistics
import seaborn as sns
datasets = {'iris1': sns.load_dataset('iris'), 'iris2': sns.load_dataset('iris')}
def testing(data):
rows = []
for i in range(1,3):
test=data[f'iris{i}']
rows.append([
statistics.mean(test['sepal_length']),
statistics.mean(test['sepal_width'])
])
testing(datasets)
No...
You should NEVER make a sentence like I have dataframes that follow name syntax of 'df#'
Then you have a list of dataframes, or a dict of dataframe, depending how you want to index them...
Here I would say a list
Then you can forget about vars(), trust me you don't need it... :)
EDIT :
And use list comprehensions, your code could hold in three lines :
import statistics
list_iris = [sns.load_dataset('iris'), sns.load_dataset('iris')]
rows = [
(statistics.mean(test['sepal_length']), statistics.mean(test['sepal_width']))
for test in list_iris
]
Storing as a list or dictionary allowed me to create the function. There is still a problem of the nubmer of dataframes in the list varies. It would be nice to be able to just input n argument specifying how many objects are in the list (I guess I could just add a bunch of if statements to define the list based off such an argument). **EDIT: Changing my code so that I don't use df# syntax, instead just putting it directly into a list
The problem I was experiencing is still perplexing. I can't for the life of me figure out why the "test" variable performs as expected outside of a function, but inside of a function it fails. I'm going to go the route of creating a list of dataframes, but am still curious to understand why it fails inside of the function.
I agree with #Icarwiz that it might not be the best way to go about it but you can make it work with.
test=eval('iris'+str(i+1))

Python: Easy way to loop through dictionary parameters from a list of evaluated strings?

I have a dictionary created from a json file. This dictionary has a nested structure and every few weeks additional parameters are added.
I use a script to generate additional copies of the existing parameters when I want multiple "legs" added. So I first add the additional legs. So say I start with 1 leg as my template and I want 10 legs, I will just clone that leg 9 more times and add it to the list.
Then I loop through each of the parameters (called attributes) and have to clone certain elements for each leg that was added so that it has a 1:1 match. I don't care about the content so cloning the first leg value is fine.
So I do the following:
while len(data['attributes']['groupA']['params']['weights']) < legCount:
data['attributes']['groupA']['params']['weights'].append(data['attributes']['groupA']['params']['weights'][0])
while len(data['attributes']['groupB']['paramsGroup']['factors']) < legCount:
data['attributes']['groupB']['paramsGroup']['factors'].append(data['attributes']['groupB']['paramsGroup']['factors'][0])
while len(data['attributes']['groupC']['items']['delta']) < legCount:
data['attributes']['groupC']['items']['delta'].append(data['attributes']['groupC']['items']['delta'][0])
What I'd like to do is make these attributes all strings and just loop through them dynamically so that when I need to add additional ones, I can just paste one string into my list and it works without having another while loop.
So I converted it to this:
attribs = [
"data['attributes']['groupA']['params']['weights']",
"data['attributes']['groupB']['paramsGroup']['factors']",
"data['attributes']['groupC']['items']['delta']",
"data['attributes']['groupD']['xxxx']['yyyy']"
]
for attrib in attribs:
while len(eval(attrib)) < legCount:
eval(attrib).append(eval(attrib)[0])
In this case eval is safe because there is no user input, just a defined list of entries. Tho I wouldn't mind finding an alternative to eval either.
It works up until the last line. I don't think the .append is working on the eval() result. It's not throwing an error.. just not appending to the element.
Any ideas on the best way to handle this?
Not 100% sure this will fix it, but I do notice one thing.
In your above code in your while condition you are accessing:
data['attributes']['groupA']['params']['weights']
then you are appending to
data['attributes']['groupA']['params']['legs']
In your below code it looks like you are appending to 'weights' on the first iteration. However, this doesn't explain the other attributes you are evaluating... just one red flag I noticed.
Actually my code was working. I was just checking the wrong variable. Thanks Me! :)

In Python, is there a way to save an index subset of an array to use again later?

My code currently has an array, lets say for example:
arr = np.ones((512, 512)).
There is an area of the array that interests me. I usually access it like this:
arr[50:200,150:350] #do stuff here.
I was wondering, is there some way to make a variable that holds [50:200,150:350]? This way, if I need to slightly change my mask, I can do it once, on the top of the file, instead of everywhere it is accessed.
I tried mask = [50:200,150:350], arr[mask] but Python syntax won't allow that.
Thanks for the help!
Apparently numpy extends slicing and allows multiple slice() objects, one per dimension.
import numpy
o = numpy.ones((32, 32))
print(o[3:5,3:5])
foo = slice(3,5), slice(3,5)
print(o[foo])
Both incantations produce same result :)

writing a python script that calls different directories

It's kind of hard to explain but I'm using a directory that has a number of different files but essentially I want to loop over files with irregular intervals
so in pseudocode I guess it would be written like:
A = 1E4, 1E5, 5E5, 7E5, 1E6, 1.05E6, 1.1E6, 1.2E6, 1.5E6, 2E6
For A in range(start(A),end(A)):
inputdir ="../../../COMBI_Output/Noise Studies/[A] Macro Particles/10KT_[A]MP_IP1hoN0.0025/"
Run rest of code
Because at the moment I'm doing it manually by changing the value in [A] and its a nightmare and time consuming. I'm using Python on a macbook so I wonder if writing a bash script that is called within Python would be the right idea?
Or replacing A with a text file, such that its:
import numpy as np
mpnum=np.loadtxt("mp.txt")
for A in range(0,len(A)):
for B in range(0,len(A)):
inputdir ="../../../COMBI_Output/Noise Studies/",[A] "Macro Particles/10KT_",[A]"MP_IP1hoN0.0025/"
But I tried this first and still had no luck.
You are almost there. You don't need a range, just iterate over the list. Then do a replacement in the string using format.
A = ['1E4', '1E5', '5E5', '7E5', '1E6', '1.05E6', '1.1E6', '1.2E6', '1.5E6', '2E6']
for a in A:
inputdir = "../../../COMBI_Output/Noise Studies/{} Macro Particles/10KT_{}MP_IP1hoN0.0025/".format(a)
The idea of putting the file names in a list and simply iterating over them using
for a in A:
seems to be the best idea. However, one small suggestion, if I may, instead of having a list, if you're going to have a large number of files inside this list, why not make it a dictionary? In this way, you can iterate through your files easily as well as keep a count on them.

Categories