Python and plotting the histograms (using matplotlib) - python

My problem in general: I have a function, that creates and saves the histograms. In my code I run the function twice: 1st time to create and save one plot with one data array, 2nd time to create and save second plot with another data array.
After the completion of the program, I get 2 .png files: the 1st one contains the histogram of one data array, the 2nd one contains histogram of the first AND the second data arrays!
What I need is one plot for one array, and second plot for another array. My mind's gonna blow, I just can't get, what's wrong here. Might somebody give me a clue?
Here's a part of my code and resulting images:
def mode(station_name, *args):
...
#before here the 'temp' data array is generated
temp_counts = {}
for t in temp:
if t not in temp_counts:
temp_counts[t] = 1
else:
temp_counts[t] += 1
print(temp_counts) **#this dictionary has DIFFERENT content being printed in two function runs**
x = []
for k, v in temp_counts.items():
x += [k for _ in range(v)]
plt.hist(x, bins="auto")
plt.grid(True)
plt.savefig('{}.png'.format(station_name))
#---------------------------------------------------------------------------------------------------
mode(station_name, [...])
mode(station_name, [...])
the 'like' of 1 image i get
the 'like' of 2 image i get
real images i get after my full script finishes #1
real images i get after my full script finishes #2

If you use plt.plotsomething.. the plot is added to the current figure in use, therefore the second histogram is added to the first. I suggest using the matplotlib object API to avoid confusion: you create figure and axis and you generate your plots starting from them. Here's your code:
def mode(station_name, *args):
...
#before here the 'temp' data array is generated
temp_counts = {}
for t in temp:
if t not in temp_counts:
temp_counts[t] = 1
else:
temp_counts[t] += 1
print(temp_counts) **#this dictionary has DIFFERENT content being printed in two function runs**
x = []
for k, v in temp_counts.items():
x += [k for _ in range(v)]
fig, ax = plt.subplots(1):
ax.hist(x, bins="auto")
ax.grid(True)
fig.savefig('{}.png'.format(station_name))
#---------------------------------------------------------------------------------------------------
mode(station_name, [...])
mode(station_name, [...])
This should do the job for you

Related

How do I store my results which are of the form of graphs and numerical outputs/ Is there a universal way of storing any kind of result in python?

I am writing a program that runs for a long time. I want to run this program many times so that I can see the dependence of my results on the tweaking of parameters.
So, suppose a situation similar to the following:
parameter=1
"Big code that takes a long time"
print(output, "output that depends on t")
plt.plot(x,y)
Now change the parameter to 2 and re-run again. I want to be able to pull the results of the previous one so that I can compare them.
So I want to sort of store them somehow so that the next time I need to look at the results I just have to execute a few lines and the stored results come up really quickly.
You can store all the information such as the inputs, params, and outputs in a dictionary. You can then use the dict to do further plotting and analysis.
Here I add a minimal reproducible example. You can use this as a reference for your needs. The below code produces this plot as an output.
import matplotlib.pyplot as plt
import numpy as np
import random
def big_code(param, input):
output = [i + param**(random.randrange(2, 5)) for i in input]
return output
def plot_experiments(info):
rows, cols = 1, 6
_, axs = plt.subplots(rows,cols)
i = 0
for val in info.values():
param_idx = val['param']
axs[i].plot(val['input'], val['output'])
axs[i].set_title(f'param {param_idx}')
i+=1
for ax in axs.flat:
ax.set(xlabel='x-label', ylabel='y-label')
# Hide x labels and tick labels for top plots and y ticks for right plots.
for ax in axs.flat:
ax.label_outer()
plt.show()
if __name__ == '__main__':
input_params = [1,2,3,4,5,6]
input_list = np.array(list(range(2000)))
info = {}
for exp_id ,param in enumerate(input_params):
# Run your big code to get output
output = big_code(param, input_list)
# Save your output to a dataframe
info[exp_id] = {'input': input_list, 'output': output, 'param': param }
# Access your dict and plot
plot_experiments(info)

Is there any way to create a number of equal class objects in a for loop in Python?

I started learning Python about a month ago because I need it for a project at University, so I apologize in advance for any conceptual mistakes or erroneous assumptions I may make in my explanation.
Before explaining my problem, I checked a couple of questions like the following, but I don't think the answers are what I need:
Python create objects in for loop
The program simulates the trajectories of a number of fluid particles. The way I do this is by creating a 'line' and a 'dot' object that will store the values of the x- and y-coordinates of the particles and then animating them with matplotlib:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import math
# initializing the figure in
# which the graph will be plotted
fig = plt.figure()
# setting limits for both the x-axis and y-axis
axis = plt.axes(xlim =(0, 20),
ylim =(-2, 50))
# initializing a line variable for each
# trajectory to be plotted
line1, = axis.plot([], [], lw = 1)
line2, = axis.plot([], [], lw = 1)
redDot, = plt.plot([1], [10], 'ro', markersize = 2)
# data which the line will
# contain (x, y). Lines are
# initially empty objects
def init():
line1.set_data([], [])
line2.set_data([], [])
return line1, line2
# initializing empty values
# for x and y coordinates
xdata1, ydata1 = [], []
xdata2, ydata2 = [], []
# animation function
def animate(i):
# t is a parameter which varies
# with the frame number
t = 0.1 * i
# x, y values to be plotted
x = math.exp(t)
y = 1 + (2/3)*t**(3/2)
# appending values to the previously
# empty x and y data holders
xdata1.append(x)
ydata1.append(y)
line1.set_data(xdata1, ydata1)
x = math.exp(t)
y = 10 + (2/3)*t**(3/2)
# appending values to the previously
# empty x and y data holders
xdata2.append(x)
ydata2.append(y)
line2.set_data(xdata2, ydata2)
redDot.set_data(x, y)
return line1, line2, redDot
anim = FuncAnimation(fig, animate, init_func = init,
frames = 200, interval = 20, blit = True)
The code above creates a line where it says line1, = axis.plot([], [], lw = 1). Immediately after that, it creates a point with redDot, = plt.plot([1], [10], 'ro', markersize = 2), which will follow the line. The problem is I intend to simulate 10 particles at the same time, and I believe there must be a cleaner, more efficient way to create all these objects than having to repeat those two lines of code 10 times. What's more, there are two lists that act as data holders for each particle, and the animate function needs to go through all of them too to assign the calculated values. It would make for a very lengthy code, and it would be downright impractical if I wanted to animate a larger number of particles.
Is there any way to do that with a loop? Something like:
for i in list(range(number_of_particles)):
#number_of_particles lines and dots are created here
I'm wondering if I could store these objets in a list, such as:
my_list = []
for i in list(range(number_of_particles)):
my_list.append(axis.plot([], [], lw = 1))
Then I would only have to call the items of said list in another for loop.
Again, I am just a newbie and I really appreciate any input from anyone who might want to help. Thanks!
I think your own suggestions work more or less, which I have just adapted here below.
To create a list of Matplotlib.lines.Line2D instances
number_of_particles = 10
lines = [axis.plot([], [], lw=1)[0] for i in range(number_of_particles)]
Storing the data for each line: Create a list to store the x and y data for each line, you can do the following, which simply creates a list of tuples, where each tuple contains a list for the x-coordinates and a list for the y-coordinates. This is similar to the spirit of your xdata1, ydata1 = [], [], but just a list of such tuples.
lines_data = [([], []) for i in range(number_of_particles)]
Updating each of the lines in the animate function. Here the built-in enumerate function gets you both the index of the ith iteration so you can use it in the loop, and the item in the iterable list. I suppose to have more flexibility in the functions you could perhaps add the constants to lists and then index them with i if needed.
for i, line in enumerate(lines):
x = math.exp(t)
y = i + (2/3)*t**(3/2)
lines_data[i][0].append(x)
lines_data[i][1].append(y)
line.set_data(lines_data[i][0], lines_data[i][1])
Smart way to return a list. When returning use a * to have the list unpacked. Have just added the lines list to the existing return statement.
return line1, line2, redDot, *lines
Finally, I was not fully sure about the comment
What's more, there are two lists that act as data holders for each
particle, and the animate function needs to go through all of them too
to assign the calculated values.
Maybe you could elaborate on that, but it seems that the new computations are just appended to the end, which I suppose shouldn't have the worst impact.

How can I plot multiple line in the same graph in python?

I want to create this graph 1 in python using matplotlib. I created a list called generation that is initialized with values from 0 to 200. I created a list variable consisting of 38 lists. Each list consists of 200 float numbers. I tried to plot the data but I have the error:
ValueError: x and y must have same first dimension, but have shapes (200,) and (38,)
My code:
generation = []
for i in range(200):
generation.append(i)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.title("A test graph")
for i in range(len(listt)):
#generation is a list with 200 values
#listt is a list with 38 lists
#list1 is a list with 200 values
plt.plot(generation ,[list1[i] for list1 in listt],label = 'id %s'%i)
plt.legend()
plt.show()
The final graph I want to look like the one below:
Each line in this graph 1 corresponds to a different input value. For each input, the algorithm runs 100 generations. The graph shows how the results of the algorithm evolve over 100 generations.
You're almost there! You only need to use listt[i] instead of [list1[i] for list1 in listt].
So, the code should look like this:
import matplotlib.pyplot as plt
#random listt
listt = [[i for j in range(200)] for i in range(38)]
generation = []
for i in range(200):
generation.append(i)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.title("A test graph")
for i in range(len(listt)):
plt.plot(generation ,listt[i],label = 'id %s'%i) #<--- change here
plt.legend()
plt.show()
And it returns this graph:
Of course, it won't be exactly as yours since I randomly generated listt.

Plot overwriting in for loop

I'm using FeniCS to solve a PDE at different time-steps which I then store into various lists and plot in python using matplotlib. I'm having problems trying to create and save multiple (three) plots in a loop. I can only manage to save one plot without them overwriting. Neglecting necessary details, my code looks like this
for n in range(num_steps):
#Update current time
t += dt
#Solve
solve(a_form == L_form, u)
#Store times
t_vals.append(t)
#Solve PDE, gives solution u
solve(u)
#Create empty lists
u_vals_x = []
u_vals_y = []
u_vals_z = []
#Set constant
xyz_fixed_density = 1000
#Store u values varying x, y and z held equal to 1
for n in np.linspace(x0,x1,xyz_fixed_density):
u_vals_x.append(u(n,1,1))
#Store u values varying y, x and z held equal to 1
for n in np.linspace(y0,y1,xyz_fixed_density):
u_vals_y.append(u(1,n,1))
#Store u values varying z, x and y held equal to 1
for n in np.linspace(z0,z1,xyz_fixed_density):
u_vals_z.append(u(1,1,n))
#First plot
plt.scatter(np.linspace(x0,x1,xyz_fixed_density),u_vals_x,s=1)
plt.legend(t_vals)
plt.xlabel('$x$')
plt.ylabel('$u(t,x,1,1)$')
plt.savefig('u_vs_x.png')
#Second plot
plt.scatter(np.linspace(y0,y1,xyz_fixed_density),u_vals_y,s=1)
plt.legend(t_vals)
plt.xlabel('$y$')
plt.ylabel('$u(t,1,y,1)$')
plt.savefig('u_vs_y.png')
#Third plot
plt.scatter(np.linspace(z0,z1,xyz_fixed_density),u_vals_z,s=1)
plt.legend(t_vals)
plt.xlabel('$z$')
plt.ylabel('$u(t,1,1,z)$')
plt.savefig('u_vs_z.png')
It's probably a simple fix but I can't seem to get it to work. Thanks in advance.
Use the current iteration (n) as part of the filenames; e.g. replace
plt.savefig('u_vs_x.png')
with
plt.savefig(f'u_vs_x_{n}.png')
This uses the f-string syntax to format the code. If you’re using an older Python version which does not support f-strings yet, use format explicitly:
plt.savefig('u_vs_x_{}.png'.format(n))
You’ll also need to create a new plot each time, e.g. via
plt.figure()

lmfit matplot - fitting many curves from many different files at the same time/graph

I have the following code, with which I intend to read and plot many curves from many different files. The "reading and plotting" is already working pretty good.
The problem is that now I want to make a fitting for all those curves in the same plot. This code already manages to fit the curves, but the output is all in one array and I can not plot it, since I could not separate it.
#!/usr/bin/python
import matplotlib.pyplot as plt
from numpy import exp
from lmfit import Model
def read_files(arquivo):
x = []
y = []
abscurrent = []
time = []
data = open(arquivo, 'r')
headers = data.readlines()[60:]
for line in headers:
line = line.strip()
X, Y, ABS, T = line.split('\t')
x.append(X)
y.append(Y)
abscurrent.append(ABS)
time.append(T)
data.close()
def J(x, j, n):
return j*((exp((1.6e-19*x)/(n*1.38e-23*333)))-1)
gmod = Model(J)
result = gmod.fit(abscurrent, x=x, j=10e-10, n=1)
return x, y, abscurrent, time
print(result.fit_report())
When I ask to print the "file" result.best_fit, which in the lmfit would give the best fit for that curve, I get 12 times this result (I have 12 curves) , with different values:
- Adding parameter "j"
- Adding parameter "n"
[ 4.30626925e-17 3.25367918e-14 9.60736218e-14 2.20310475e-13
4.63245638e-13 9.38169958e-13 1.86480698e-12 3.67881758e-12
7.22634738e-12 1.41635088e-11 2.77290634e-11 5.42490983e-11
1.06108942e-10 2.07520542e-10 4.05768903e-10 7.93323537e-10
1.55126521e-09 3.03311029e-09 5.93085363e-09 1.16032067e-08
2.26884736e-08 4.43641560e-08 8.67362753e-08 1.69617697e-07
3.31685858e-07 6.48478168e-07]
- Adding parameter "j"
- Adding parameter "n"
[ 1.43571772e-16 1.00037588e-13 2.92349492e-13 6.62623404e-13
This means that the code is calculating the fit correctly, I just have to separate this output somehow in order to plot each of them with the their curve. Each set of values between [] is what I want to separate in a way I can plot it.
I do not see how the code you posted could possibly produce your output. I do not see a print() function that prints out the array of 26 values, but would imagine that could be the length of your lists x, y and abscurrent -- it is not the output of your print(result.fit_report()), and I do not see that result.
I do not see anything to suggest you have 12 independent curves.
Also, result.best_fit is not a file, it is an array.

Categories