Merge dataframes with mirrored values - python

I have a dataframe which stores measurement points of an circular area. So each point has a Radius_mm and Angle_deg value.
As a visual representation of the data, I would now like to create a section through the surface. I.e. I choose one angle and the corresponding angle that lies at 180° to it, including the center.
The x-axis should display the Radius_mm and the y-axis the Value.
I could nearly archive this, as shown below. By plotting each data set separately, the result is unfortunatly not connected. I am sure there is a more elegant way, but couldn't get to it, can some help?
Thanks!
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame(
{
"Point": (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
"Radius_mm": (0, 0.5, 0.5, 0.75, 0.75, 1.25, 1.25, 1.75, 1.75, 2, 2, 2.25, 2.25, 2.5, 2.5),
"Angle_deg": (0, 45, 225, 45, 225, 45, 225, 45, 225, 45, 225, 45, 225, 45, 225),
"Value": (70, 68, 66.75, 68.08, 66.72, 68.44, 67.31, 68.82, 68.02, 68.93, 68.41, 69.39, 68.3, 68.54, 68.55),
}
)
# first angle
filtered_df = df.loc[df["Angle_deg"] == 45]
# second angle = first angle + 180°
filtered_df2 = df.loc[df["Angle_deg"] == 225]
# x values ("mirrored")
xvalues_for_mirrored_angle = [x*-1 for x in filtered_df2["Radius_mm"].tolist()]
# center value
filtered_df3 = df.loc[df["Angle_deg"] == 0]
xvalue_center = [x for x in filtered_df3["Radius_mm"].tolist()]
# combining x axis values
xtick_values = xvalues_for_mirrored_angle + xvalue_center + filtered_df["Radius_mm"].tolist()
fig, ax = plt.subplots()
ax.plot("Radius_mm", "Value", data=filtered_df, marker="+", label=(f"Angle = 45"))
ax.plot(xvalues_for_mirrored_angle, "Value", data=filtered_df2, marker="+", label=(f"Angle = 225"))
ax.plot("Radius_mm", "Value", data=filtered_df3, marker="+", label=(f"Angle = Center"))
ax.grid(True)
ax.set_xticks(xtick_values)
ax.set_xticklabels(xtick_values, rotation = 45)
ax.set_xlabel("Radius")
ax.legend(fontsize=10)
fig.tight_layout()
plt.show()

You don't need the filtered_dfs, you can do most of this in a couple of lines of Pandas, and keep the line connected:
df = pd.DataFrame(... # as above
df.loc[df.Angle_deg==225, 'Radius_mm'] *= -1 # flip the reverse angle
df = df.sort_values(by='Radius_mm')
then the plot:
df.plot(x='Radius_mm', y='Value', marker='+', legend=False, grid=True, xlabel='radius', xticks=df['Radius_mm'], rot=45);
If you want to keep the colours separate, you can replace the last line with this:
f, ax = plt.subplots()
ax.plot("Radius_mm", "Value", data=df, marker="+", label=(f"Angle = 0"))
ax.plot("Radius_mm", "Value", data=df[df["Angle_deg"] == 45], marker="+", label=(f"Angle = 45"))
ax.plot("Radius_mm", "Value", data=df[df["Angle_deg"] == 225], marker="+", label=(f"Angle = 225"))
ax.grid(True)
ax.set_xticks(df["Radius_mm"])
ax.set_xticklabels(df["Radius_mm"], rotation = 45)
ax.set_xlabel("Radius")
ax.legend(fontsize=10)
f.tight_layout()
plt.show()

Related

Show previously created pandas plot

Say I create a bar plot in a Jupyter notebook:
import pandas as pd
import matplotlib.pyplot as plt
speed = [0.1, 17.5, 40, 48, 52, 69, 88]
lifespan = [2, 8, 70, 1.5, 25, 12, 28]
index = ["snail", "pig", "elephant", "rabbit", "giraffe", "coyote", "horse"]
df = pd.DataFrame({"speed": speed, "lifespan": lifespan}, index=index)
plot = df.plot(kind='bar', stacked=True)
This shows my chart.
Then, in the next cell, I make a modification, e.g. adding data labels:
for bar in plot.patches:
height = bar.get_height()
width = bar.get_width()
x = bar.get_x()
y = bar.get_y()
label_text = height
label_x = x + width / 2
label_y = y + height / 2
if label_text != 0:
plot.text(
label_x,
label_y,
int(label_text),
ha="center",
va="center",
color="white",
fontweight="bold",
)
Now, how can I show the plot again? plt.show() returns nothing.
Just show the figure again:
plot.figure
As an alternative, you can use plot.get_figure().

Get matplotlib automatic y tick values in a list

Edit:
I tried the following.
auto_y_ticks=list(axes2.get_yticklabels())
But still the output is not a list of tick values. It shows as Matplotlib text.
The following code produces bar and line plot in the same graph.
In the secondary y axis, the ytick values range from -1 to +1.
My question is, how do I store these values in a list?
from matplotlib import pyplot as plt
import numpy as np
plt.figure()
N = 5
menMeans = (20, 35, 30, 35, 27)
menStd = (2, 3, 4, 1, 2)
width = 0.35 # the width of the bars
womenMeans = (25, 32, 34, 20, 25)
womenStd = (3, 5, 2, 3, 3)
ind = np.arange(N)
plt.ylim(0.0, 65.0)
plt.bar(ind, menMeans, width, color='r', yerr=menStd, label='Men means')
plt.bar(ind+width, womenMeans, width, color='y', yerr=womenStd, label='Women means')
plt.ylabel('Bar plot')
x = np.linspace(0, N)
y = np.sin(x)
axes2 = plt.twinx()
axes2.plot(x, y, color='k', label='Sine')
axes2.set_ylim(-1, 1)
axes2.set_ylabel('Line plot')
plt.show()
auto_y_ticks=list(What's the logic)
Starting from your code,
axes2.get_yticks()
gives
array([-1. , -0.75, -0.5 , -0.25, 0. , 0.25, 0.5 , 0.75, 1. ])
Which is what you're after, right?

Mathplotlib pandas-Plotting average line to scatter plot?

I have a scatter plot created from two columns of a pandas data frame and I would like to add a line across each axis representing the average. Is this possible with a scatter plot?
plt.title("NFL Conversion Rates", fontsize=40)
# simulating a pandas df['team'] column
types = df.Tm
x_coords = df['3D%']
y_coords = df['4D%']
binsy = [15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85]
binsx = [30,35,40,45,50,55]
avg_y = y_coords.mean()
avg_y = round(avg_y, 1)
display(avg_y)
avg_x = x_coords.mean()
avg_x = round(avg_x, 1)
display(avg_x)
for i,type in enumerate(types):
x = x_coords[i]
y = y_coords[i]
plt.scatter(x, y, s=30, marker='o', edgecolor='black', cmap='purple', linewidth=1, alpha = 0.5)
plt.text(x+0.2, y+0.1, type, fontsize=14)
plt.xlabel('3rd Down Conversion Percentage',fontsize=30)
plt.ylabel('4th Down Conversion Percentage', fontsize=30)
plt.xticks(binsx)
plt.yticks(binsy)
You can try
plt.axvline(<value>,color='red',ls='--') and plt.axhline(<value>,color='red',ls='--'). Substitute with the value at which you want the lines

Python - matlibplot - control figure size

I have some problems on controlling the figure size when using matlibplot. I want the figure to be 9cm * 14.5 cm in size exactly. I use "figsize" command to control the figure size; however, the figure exceeds the specified size. Please advise how to achieve this.
The python codes are attached as follows:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize = (9/2.54, 14.5/2.54), nrows = 2, ncols = 1)
ax[0] = plt.subplot(2, 1, 1)
x1 = [30, 40, 50, 60, 70, 80, 90, 100]
y1 = [6, 7, 8, 9, 10, 11, 12, 13]
ax[0].plot(x1, y1, 'r-s', label = 'XXXXXXXX')
ax[0].set_xlabel('Percentage load (%)')
ax[0].set_ylabel('Output parameter (%)')
ax[0].legend(loc = (0.05, 0.8))
ax[0].text(0.05, 0.7, '(a)', transform = ax[0].transAxes)
ax[0].set_xlim(x1[0], x1[-1])
x2 = [30, 40, 50, 60, 70, 80, 90, 100]
y2 = [6, 7, 8, 9, 10, 11, 12, 13]
ax[1] = plt.subplot(2, 1, 2)
ax[1].plot(x2, y2, 'k-o', label = 'YYYYYYYYY')
ax[1].set_xlabel('Percentage load (%)')
ax[1].set_ylabel('Output parameter (%)')
ax[1].legend(loc = (0.05, 0.8))
ax[1].text(0.05, 0.7, '(b)', transform = ax[1].transAxes)
ax[1].set_xlim(x2[0], x2[-1])
plt.subplots_adjust(top=1, bottom=0.0, left=0.0, right=1, hspace=0.2, wspace=0.0)
plt.savefig(fname = '2figax.png', dpi = 600, quality = 95, bbox_inches = 'tight', pad_inches = None)

Polar chart with limit and anomalous points

Consider the following data frame,
d = {'Score': [0.25, 0.52, 0.26, 0.22, 0.31, 2.45, 3.68, 41.3, 87, 91],
'Thr1': 16.5,
'Thr2': 45.5,
'Anomaly':[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]}
df = pd.DataFrame(data = d)
What I m trying to do is to plot a polar chart, with a dotted line for threshold or multiple dotted lines for multiple thresholds and different color for the anomalies. What I ve got so far is,
r = df['Score']
theta = df.index.values
fig = plt.figure()
ax = fig.add_subplot(111, projection = 'polar')
c = ax.scatter(theta, r)
I cannot get the threshold though and change the color of the anomalous points. Any ideas?
You need to draw a dashed line at the threshold level, to indicate where the threshold is. (a line will appear as a circle on a polar plot).
Then you need to segregate the values to plot on the scatter plot, based whether or not they are below, between, or above the thresholds, and color the points accordingly.
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
dataset = {'Score': [0.25, 0.52, 0.26, 0.22, 0.31, 2.45, 3.68, 41.3, 87, 91],
'Thr1': 16.5,
'Thr2': 45.5,
'Anomaly':[0, 0, 0, 0, 0, 0, 0, 1, 1, 1]}
df = pd.DataFrame(data=dataset)
scores = df['Score']
theta, thr_1, thr_2 = df.index.values, dataset['Thr1'], dataset['Thr2']
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
# assigns a color to each point based on their relative value to the thresholds
colors = ['b' if val < thr_1 else 'y' if val < thr_2 else 'r' for val in scores]
point_cloud = ax.scatter(theta, scores, color=colors, marker='o')
# Drawing the threshold dash lines (with alpha value 1/2)
theta_xs, thr_y1, thr_y2 = np.linspace(0, 2*np.pi, 20), [thr_1] * 20, [thr_2] * 20
thr_line_1 = ax.plot(theta_xs, thr_y1, color='blue', linestyle='--', alpha=0.5)
thr_line_2 = ax.plot(theta_xs, thr_y2, color='green', linestyle='--', alpha=0.5)
plt.show()
Well, i'm not exactly sure that it is what you want, because i never used Anomaly part of your dataset, and just take color info from Score array
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as c
d = {'Score': [0.25, 0.52, 0.26, 0.22, 0.31, 2.45, 3.68, 41.3, 87, 91],
'Thr1': 16.5,
'Thr2': 45.5,
'Anomaly': [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]}
df = pd.DataFrame(data = d)
r = df['Score']
theta = df.index.values
fig = plt.figure()
ax = fig.add_subplot(111, projection = 'polar')
#Add thresholds
ax.plot(np.linspace(0, 2*np.pi, 100), np.ones(100)*d['Thr1'], c='g', ls='--')
ax.plot(np.linspace(0, 2*np.pi, 100), np.ones(100)*d['Thr2'], c='r', ls='--')
#Add colors
colors = ['g' if v < d['Thr1'] else 'y' if v < d['Thr2'] else "r" for v in r]
sc = ax.scatter(theta, r, c=colors)
plt.show()

Categories

Resources