How to plot multiple animations in Matplolib for 2 different processes - python

In a measurement chain, each instrument embedded in various measurement loops will record a CSV and I want to monitor the live plots in separate figures i.e figure 1 for instrument1 , figure 2 for instrument2...etc. I try to implement animations but nothing out. csv is continuously generating data.
I first generate data in a CSV then i try to plot 2 animations in parallel:I get the figure 2 animated but the first is frozen. any help appreciated.
import pandas as pd
from matplotlib import pyplot as plt
from matplotlib import animation
# making figures
def makeFigure():
df = pd.read_csv('data.csv')
data = pd.DataFrame(df)
x = data['current']
y1 = data['resistance']
y2 = data['voltage']
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
# # Plot 1 set of data
dataset =ax.plot(x,y1)
return fig,ax,dataset
# Frame rendering function
def renderFrame(i, dataset):
df = pd.read_csv('data.csv')
data = pd.DataFrame(df)
x = data['current']
y1 = data['resistance']
y2 = data['voltage']
# Plot data
plt.cla()
dataset, =ax.plot(x,y2)
return dataset
# Make the figures
figcomps1=makeFigure()
figcomps2=makeFigure()
# List of Animation objects for tracking
anim = []
# Animate the figures
for figcomps in [figcomps1,figcomps2]:
fig,ax,dataset = figcomps
anim.append(animation.FuncAnimation(fig,renderFrame,fargs=[dataset]))
# plt.gcf()
plt.show()
```

Related

How to draw a figure by seaborn pairplot in several rows?

I have a dataset with 76 features and 1 dependent variable (y). I use seaborn to draw pairplot between features and y in Jupyter notebook. Since the No. of features is high, size of plot for every feature is very small, as can be seen below:
I am looking for a way to draw pairplot in several rows. Also, I don't want to copy and paste pairplot code in several cells in notebook. I am looking for a way to make this figure automatically.
The code I am using (I cannot share dataset, so I use a sample dataset):
from sklearn.datasets import load_boston
import math
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
X, y = load_boston(return_X_y=True)
X = pd.DataFrame(X)
y = pd.DataFrame(y)
data = pd.concat([X, y], axis=1)
y_name = 'y'
features_names = [f'feature_{i}' for i in range(1, X.shape[1]+1)]
column_names = features_names + [y_name]
data.columns = column_names
plot_size=7
num_plots_x=5 # No. of plots in every row
num_plots_y = math.ceil(len(features_names)/num_plots_x) # No. of plots in y direction
fig = plt.figure(figsize=(plot_size*num_plots_y, plot_size*num_plots_x), facecolor='white')
axes = [fig.add_subplot(num_plots_y,1,i+1) for i in range(num_plots_y)]
for i, ax in enumerate(axes):
start_index = i * num_plots_x
end_index = (i+1) * num_plots_x
if end_index > len(features_names): end_index = len(features_names)
sns.pairplot(x_vars=features_names[start_index:end_index], y_vars=y_name, data = data)
plt.savefig('figure.png')
The above code has two problems. It shows empty box at the top of the figure and then it shows the pairplots. Following is part of the figure that I get.
Second problem is that it only saves the last row as png file, not the whole figure.
If you have any idea to solve this, please let me know. Thank you.
When I run it directly (python script.py) then it opens every row in separated window - so it treats it as separated objects and it saves in file only last object.
Other problem is that sns doesn't need fig and axes - it can't use subplots to put all on one image - and when I remove fig axes then it stops showing first window with empty box.
I found that FacetGrid has col_wrap to put in many rows. And I found that someone suggested to add this col_wrap in pairplot - Add parameter col_wrap to pairplot #2121 and there is also example how to FacetGrid with scatterplot instead of pairplot and then it can use col_wrap.
Here is code which use FacetGrid with col_wrap
from sklearn.datasets import load_boston
import math
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
X, y = load_boston(return_X_y=True)
X = pd.DataFrame(X)
y = pd.DataFrame(y)
data = pd.concat([X, y], axis=1)
y_name = 'y'
features_names = [f'feature_{i}' for i in range(1, X.shape[1]+1)]
column_names = features_names + [y_name]
data.columns = column_names
plot_size=7
num_plots_x=5 # No. of plots in every row
num_plots_y = math.ceil(len(features_names)/num_plots_x) # No. of plots in y direction
'''
for i in range(num_plots_y):
start = i * num_plots_x
end = start + num_plots_x
sns.pairplot(x_vars=features_names[start:end], y_vars=y_name, data=data)
'''
g = sns.FacetGrid(pd.DataFrame(features_names), col=0, col_wrap=4, sharex=False)
for ax, x_var in zip(g.axes, features_names):
sns.scatterplot(data=data, x=x_var, y=y_name, ax=ax)
g.tight_layout()
plt.savefig('figure.png')
plt.show()
Result ('figure.png'):

Plotting multiple colored lines and vectors in 3D with matplotlib

I'm struggling to create a 3-D plot with multiple colored lines and vectors in matplotlib. The end result should look as follows:
I already found this question. The code
from mpl_toolkits.mplot3d.axes3d import Axes3D
import matplotlib.pyplot as plt
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
datasets = [{"x":[1,2,3], "y":[1,4,9], "z":[0,0,0], "colour": "red"} for _ in range(6)]
for dataset in datasets:
ax.plot(dataset["x"], dataset["y"], dataset["z"], color=dataset["colour"])
plt.show()
results in the following output:
That's a good starting point but unfortunately not quite what I'm looking for as I don't want to have a grid in the background and clearly distinguishable coordinate axes. Furthermore, the xticks and yticks should not be visible.
Any help is highly appreciated.
I made multiple lines in Plotly.
image of plot
import plotly.express as px
import pandas as pd
#Line 1
d = {"x":[1,2], "y":[1,4], "z":[0,0], "line":[0 for i in range(2)]} #line = [0,0]. index for multible lines
df = pd.DataFrame(data=d)
#Line 2
d2 = {"x":[4,2], "y":[5,4], "z":[3,2], "line":[1 for i in range(2)]} #line = [1,1]. index for multible lines
df2 = pd.DataFrame(data=d2)
#One data frame
df = df.append(df2)
fig = px.line_3d(df, x="x", y="y", z="z", color="line")
fig.show()

How to create and save distinct scatterplots using matplotlib and nested 'for-loops' for labelled data?

I have a dataset containing 10 features and corresponding labels. I am using scatterplot to plot distinct pair of features to see which of them describe the labels perfectly (which means that total 45 plots will be created). In order to do that, I used a nested loop format. The code shows no error and I obtained all the plots as well. However, there is clearly something wrong with the code because each new scatterplot that gets created and saved is accumulating points from the previous ones as well. I am attaching the complete code which I used. How to fix this problem? Below is the link for raw dataset:
https://github.com/IITGuwahati-AI/Learning-Content/raw/master/Phase%203%20-%202020%20(Summer)/Week%201%20(Mar%2028%20-%20Apr%204)/assignment/data.txt
import pandas as pd
import matplotlib
from matplotlib import pyplot as plt
data_url ='https://raw.githubusercontent.com/diwakar1412/Learning-Content/master/DiwakarDas_184104503/datacsv.csv'
df = pd.read_csv(data_url)
df.head()
def transform_label(value):
if value >= 2:
return "BLUE"
else:
return "RED"
df["Label"] = df.Label.apply(transform_label)
df.head()
colors = {'RED':'r', 'BLUE':'b'}
fig, ax = plt.subplots()
for i in range(1,len(df.columns)):
for j in range(i+1,len(df.columns)):
for k in range(len(df[str(i)])):
ax.scatter(df[str(i)][k], df[str(j)][k], color=colors[df['Label'][k]])
ax.set_title('F%svsF%s' %(i,j))
ax.set_xlabel('%s' %i)
ax.set_ylabel('%s' %j)
plt.savefig('F%svsF%s' %(i,j))
Dataset
You have to create a new figure each time. Try to put
fig, ax = plt.subplots()
inside your loop:
for i in range(1,len(df.columns)):
for j in range(i+1,len(df.columns)):
fig, ax = plt.subplots() # <-------------- here
for k in range(len(df[str(i)])):
ax.scatter(df[str(i)][k], df[str(j)][k], color=colors[df['Label'][k]])
ax.set_title('F%svsF%s' %(i,j))
ax.set_xlabel('%s' %i)
ax.set_ylabel('%s' %j)
plt.savefig('/Users/Alessandro/Desktop/tmp/F%svsF%s' %(i,j))

Proper Matplotlib axes construction / reuse

I currently am building a set of scatter plot charts using pandas plot.scatter. In this construction off of two base axes.
My current construction looks akin to
ax1 = pandas.scatter.plot()
ax2 = pandas.scatter.plot(ax=ax1)
for dataframe in list:
output_ax = pandas.scatter.plot(ax2)
output_ax.get_figure().save("outputfile.png")
total_output_ax = total_list.scatter.plot(ax2)
total_output_ax.get_figure().save("total_output.png")
This seems inefficient. For 1...N permutations I want to reuse a base axes that has 50% of the data already plotted. What I am trying to do is:
Add base data to scatter plot
For item x in y: (save data to base scatter and save image)
Add all data to scatter plot and save image
here's one way to do it with plt.scatter.
I plot column 0 on x-axis, and all other columns on y axis, one at a time.
Notice that there is only 1 ax object, and I don't replot all points, I just add points using the same axes with a for loop.
Each time I get a corresponding png image.
import numpy as np
import pandas as pd
np.random.seed(2)
testdf = pd.DataFrame(np.random.rand(20,4))
testdf.head(5) looks like this
0 1 2 3
0 0.435995 0.025926 0.549662 0.435322
1 0.420368 0.330335 0.204649 0.619271
2 0.299655 0.266827 0.621134 0.529142
3 0.134580 0.513578 0.184440 0.785335
4 0.853975 0.494237 0.846561 0.079645
#I put the first axis out of a loop, that can be in the loop as well
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(testdf[0],testdf[1], color='red')
fig.legend()
fig.savefig('fig_1.png')
colors = ['pink', 'green', 'black', 'blue']
for i in range(2,4):
ax.scatter(testdf[0], testdf[i], color=colors[i])
fig.legend()
fig.savefig('full_' + str(i) + '.png')
Then you get these 3 images (fig_1, fig_2, fig_3)
Axes objects cannot be simply copied or transferred. However, it is possible to set artists to visible/invisible in a plot. Given your ambiguous question, it is not fully clear how your data are stored but it seems to be a list of dataframes. In any case, the concept can easily be adapted to different input data.
import matplotlib.pyplot as plt
#test data generation
import pandas as pd
import numpy as np
rng = np.random.default_rng(123456)
df_list = [pd.DataFrame(rng.integers(0, 100, (7, 2))) for _ in range(3)]
#plot all dataframes into an axis object to ensure
#that all plots have the same scaling
fig, ax = plt.subplots()
patch_collections = []
for i, df in enumerate(df_list):
pc = ax.scatter(x=df[0], y=df[1], label=str(i))
pc.set_visible(False)
patch_collections.append(pc)
#store individual plots
for i, pc in enumerate(patch_collections):
pc.set_visible(True)
ax.set_title(f"Dataframe {i}")
fig.savefig(f"outputfile{i}.png")
pc.set_visible(False)
#store summary plot
[pc.set_visible(True) for pc in patch_collections]
ax.set_title("All dataframes")
ax.legend()
fig.savefig(f"outputfile_0_{i}.png")
plt.show()

Animate Quiver plot from values in Pandas dataframe

Hi im trying to make an animation of a quiver plot from data in my data frame
I have data stored like this in a pandas DataFrame, somewhat like this
QuivXLoc QuivYLoc QuivXVal QuivYVal QuivColorVal QuivPlotNum
0 -70.22 -127.241 1.624 -0.879 1.846623 1
1 -61.74 -127.241 -0.973 -0.027 0.973375 1
2 -65.98 -121.835 0.046 2.416 2.416438 1
3 -74.46 -121.835 -0.151 2.673 2.677262 1
4 -78.70 -116.429 1.073 -0.954 1.435773 2
I am currently plotting it like this, and it generates seperate plots for each sequence number perfectly.
for seq in quidf['QuivPlotNum'].unique():
temp=quidf[quidf['QuivPlotNum']==seq] ## make subset to plot
plt.quiver(temp['QuivXLoc'], temp['QuivYLoc'], temp['QuivXVal'], temp['QuivYVal'], # data
temp['QuivColorVal'], # colour the arrows based on this array
cmap=cm.jet, # colour map
headlength=3) # length of the arrows
Theres some additional code to format the plot that I left out.
What I'd like to do is animate the sequence based on iterating through the Sequence number in my data frame. All the examples I saw for Quiver Animation involved scaling previous function by some scalar that is incremented.
example of similar quiver animation I'd like to generate, I have tried but cannot figure out how to change update_quiver to work for my application:
Plotting animated quivers in Python
Using the matplotlib.animation module and its FuncAnimation class:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
import pandas as pd
# read in the date and group it by the frame number
data = pd.read_csv('data2.csv', index_col=0)
grouped = data.groupby('QuivPlotNum')
# set up the figure
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_xlim(-200, 200)
ax.set_ylim(-200, 200)
# create empty plot for the update function to manipulate
plot = ax.quiver([], [], [], [], [], cmap='jet', headlength=3)
# create an iterator over the group, next() will return a tuple
# of QuivPlotNum, DataFrame
iterator = iter(grouped)
def update(i):
# get next thing in the iterator
key, data = next(iterator)
# set new x, y coordinates for the plot
plot.set_offsets(np.column_stack([data.QuivXLoc, data.QuivYLoc]))
# update vector and color values
plot.set_UVC(data.QuivXVal, data.QuivYVal, data.QuivColorVal)
# create the animation, update every 1000 ms
ani = FuncAnimation(fig, update, interval=1000)
# show it
plt.show()

Categories

Resources