Plot odds ratio with confidence interval python - python

I am trying to represent odds ratios in python in this way:
ax = sns.scatterplot(data=df_result, x="odd_ratio", y="iso")
plt.axvline(1.0, color='black', linestyle='--')
But I would like to have horizontal bars for each odds ratio indicating the confidence interval.
In my dataframe df_result I have the information about the lower and upper bound (df_result['lower_conf] and df_result['upper_conf]). How can I plot the confidence interval? Thanks in advance.

I share with you my code, its for a vertical plot but you can changue the axis. I have a table with the 5%, the 95% and the OR value in different columns
sns.set_style("whitegrid")
fig, ax = plt.subplots(figsize=(7, 5))
ax.set_yscale("log")
ax.axhline(1, ls='--', linewidth=1, color='black')
n = 0
for index, i in df.iterrows():
x = [n,n]
y = [i["5%"], i["95%"]]
ax.plot(x, y, "_-", markersize = 15, markeredgewidth= 3, linewidth = 3, color=sns.color_palette("muted")[n])
x = [n]
y = [i["Odds Ratio"]]
ax.plot(x, y, "o", color=sns.color_palette("muted")[n], markersize = 10)
n += 1
ax.set_xlabel("")
ax.set_ylabel("Odds Ratio")
ax.set_xticklabels(["", "Resistant", "Focal Epilepsy", "> 3 seizures/month", "Polytherapy", "DDD > 1", "Adverse effects"], rotation=45)
result

Related

Calculate distance between the center of a point on a scatter plot to the edge of it's marker, for dynamically changing marker sizes in Matplotlib

I have a scatter plot which I'd like to place by another scatter plot, however they have a dynamic marker size.
The green triangles (x, y) are calculated from the original scatter and they're close but not perfect (just from trial and error).
import pandas as pd
from mplsoccer import Pitch, VerticalPitch
data = [['JA', 35, 60, 2000], ['RN', 20, 47, 1500], ['GG', 10, 32, 1000]]
df = pd.DataFrame(data, columns=['Name', 'x', 'y', 'marker_size'])
#This is calculated from x or y length divided by marker size of biggest marker,
# divide by 2 for the radius, but the marker sizes seem to be non-linear.
df['xDiff'] = df['marker_size'] * ((7.3/2000) / 2)
df['yDiff'] = df['marker_size'] * ((11.3/2000) / 2)
df['leftArrowX'] = df['x'] - df['xDiff']
df['leftArrowY'] = df['y']
df['rightArrowX'] = df['x'] + df['xDiff']
df['rightArrowY'] = df['y']
df['downArrowY'] = df['y'] - df['yDiff']
df['downArrowX'] = df['x']
df['upArrowY'] = df['y'] + df['yDiff']
df['upArrowX'] = df['x']
pitch = Pitch(pitch_type='opta', pitch_color='#202428', line_color='#F2F2F2', linewidth=2)
fig, ax = pitch.draw(figsize=(16, 10))
players = pitch.scatter(df.x, df.y, s=df.marker_size, marker='8', color='orange', edgecolors='black', linewidth=1, alpha=1, ax=ax)
leftArrows = pitch.scatter(df.leftArrowX, df.leftArrowY, s=100, marker='<', color='lightgreen', alpha=1, ax=ax)
rightArrows = pitch.scatter(df.rightArrowX, df.rightArrowY, s=100, marker='>', color='lightgreen', alpha=1, ax=ax)
downArrows = pitch.scatter(df.downArrowX, df.downArrowY, s=100, marker='v', color='lightgreen', alpha=1, ax=ax)
upArrows = pitch.scatter(df.upArrowX, df.upArrowY, s=100, marker='^', color='lightgreen', alpha=1, ax=ax)
Result
How can I calculate the co-ordinates for the triangles more accurately given the original marker co-ordinates & marker size, so that they are placed evenly away at each point.
Or possibly any other solution to my problem.
Note: The pitch has co-ordinates 100x100, done in Jupyter Notebook. Thanks.

plt.subplots does not correctly draw sns.lineplot [duplicate]

This question already has answers here:
What is the difference between drawing plots using plot, axes or figure in matplotlib?
(2 answers)
How to add a title to each subplot
(10 answers)
Closed 11 months ago.
I have the following code:
df = sns.load_dataset('titanic')
# Data
data = df[df.age.notna()].age
# Fit a normal distribution to the data:
mu, std = scipy.stats.norm.fit(data)
# bin formulas
bin_f = {'sturges' : 1 + math.log(len(df), 2)}
# Plot the histogram.
sns.histplot( data = data, stat='density', bins=int(bin_f['sturges']), alpha=0.6, color='g', kde = True, legend = True)
# Plot the PDF.
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 1000)
p = scipy.stats.norm.pdf(x, mu, std)
sns.lineplot(x = x, y = p, color = 'black', linewidth=2)
title = f"Fit results: mu = {round(mu, 2)}, std ={round(std, 2)} "
plt.title(title)
Which produces this plot:
When I try to produce it in a subplot it wont work as expected:
f, ax = plt.subplots(nrows = 1, ncols = 2, figsize=(15, 8))
# Data
data = df[df.age.notna()].age
# Fit a normal distribution to the data:
mu, std = scipy.stats.norm.fit(data)
# bin formulas
bin_f = {'sturges' : 1 + math.log(len(df), 2)}
# Plot the histogram.
sns.histplot(ax = ax[0], data = data, stat='density', bins=int(bin_f['sturges']), alpha=0.4, color='g', kde = True, legend = True)
# Plot the PDF.
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 1000)
p = scipy.stats.norm.pdf(x, mu, std)
sns.lineplot(x = x, y = p, color = 'black', linewidth=2, ax=ax[0])
title = f"Fit results: mu = {round(mu, 2)}, std ={round(std, 2)} "
plt.title(title)
For some reason the title is only for a second plot and the previously plotted lineplot ( the black one ) is only a small tick in a second plot rather than a normal curve as in the first image. I am not sure why this is happening as the only difference is just using plt.subplots and referencing ax, where is my mistake?
My goal is to have the first graph as seen in the first picture as a the first subplot in the second plot.

Setting color of area in Matplotlib

I'm creating a chart with matplotlib, here is my code:
fig = plt.figure(facecolor='#131722',dpi=155, figsize=(8, 4))
ax1 = plt.subplot2grid((1,2), (0,0), facecolor='#131722')
Colors = [['#0400ff', '#FF0000'], ['#09ff00', '#ff8c00']]
for x in List:
Index = List.index(x)
rate_buy = []
total_buy = []
for y in x['data']['bids']:
rate_buy.append(y[0])
total_buy.append(y[1])
rBuys = pd.DataFrame({'buy': rate_buy})
tBuys = pd.DataFrame({'total': total_buy})
ax1.plot(rBuys.buy, tBuys.total, color=Colors[Index][0], linewidth=0.5, alpha=0.8)
ax1.fill_between(rBuys.buy, 0, tBuys.total, facecolor=Colors[Index][0], alpha=1)
And here is the output:
The problem with the current output is that the colors of the two areas are "merging": basically the area BELOW the blue line should be blue, but instead it's green. How can i set it to be blue, for example, like in my example?
Example List data:
[[9665, 0.07062500000000001], [9666, 0.943708], [9667, 5.683787000000001], [9668, 9.802289], [9669, 11.763305], [9670, 14.286004], [9671, 16.180122], [9672, 23.316723000000003], [9673, 30.915156000000003], [9674, 33.44226200000001], [9675, 36.14526200000001], [9676, 45.76024100000001], [9677, 51.85294700000001], [9678, 58.79529300000001], [9679, 59.05322900000001], [9680, 60.27704500000001], [9681, 60.743885000000006], [9682, 66.75103700000001], [9683, 71.86412600000001], [9684, 73.659636], [9685, 78.08502800000001], [9686, 78.19614200000001], [9687, 79.98396400000001], [9688, 90.55855800000002]]
I guess the hint of #JohanC is correct, you are plotting in the wrong order and overlay your previous plots with new ones.
I tried to recreate a small example where total_buy1 > total_buy0, so in order to get the desired result you first have to plot total_buy1
and then total_buy0:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
Colors = [['#0400ff', '#FF0000'],
['#09ff00', '#ff8c00']]
n = 100
rate_buy = np.linspace(0, 1000, 100)
total_buy0 = np.linspace(0, 300, n)[::-1] + np.random.normal(scale=10, size=n)
total_buy1 = np.linspace(0, 600, n)[::-1] + np.random.normal(scale=10, size=n)
ax.plot(rate_buy, total_buy1, color=Colors[1][1], linewidth=0.5, alpha=0.8)
ax.fill_between(rate_buy, 0, total_buy1, facecolor=Colors[1][0], alpha=1)
ax.plot(rate_buy, total_buy0, color=Colors[0][1], linewidth=0.5, alpha=0.8)
ax.fill_between(rate_buy, 0, total_buy0, facecolor=Colors[0][0], alpha=1)
I noticed that you use Colors[Index][0] for both plotting calls, so the line and the area will not have different colors.

How to change the format xticks labels and keep the colorbar of a heatmap

In this plot
inclination = np.pi/6
def power(inclination,phi):
h1=1.7
h2=0.5
D = np.arange(0.5, 12.0, 0.015)
r = np.sqrt((h1-h2)**2 + D**2)
freq = 865.7
lmb = 300/freq
H = D**2/(D**2+2*h1*h2)
theta = 4*np.pi*h1*h2/(lmb*D)
q_e = H**2*(np.sin(theta))**2 + (1 - H*np.cos(theta))**2
sigma = 1.94
N_1 = np.random.normal(0,sigma,D.shape)
rnd = 10**(-N_1/10)
F = 10
power=0.8
R,PHI = np.meshgrid(r,phi[1:-1])
alpha=inclination + np.arcsin((h1-h2)/R)
gain=3.136*(np.tan(alpha)*np.sin(np.pi/2*np.cos(alpha)*np.sin(PHI)))**2
y=10*np.log10( 1000*(power*gain*1.622*((lmb)**2) *0.5*1) / (((4*np.pi*R)**2) *1.2*1*F)*q_e*rnd )
return (R,PHI,y)
phi=np.linspace(0, np.pi,num=787)
x,y,z = power(np.pi/4,phi)
import cmocean
cmap = cmocean.cm.oxy
I would like to take out the characters x10^0 of the x ticks labels and show 2,3, 4, 6 ... and 10.
I have test a precedent post set ticks with logarithmic scale, but I cannot make it work and keep the colorbar of the heatmap.
EDIT
As suggested by #ImportanceOfBeingErnest, to plot the heatmap, I have changed the next lines
plt.contourf(x, y, z, 20, cmap=cmap)
cb=plt.colorbar();
plt.xlim(None, 12)
plt.ylim(0, np.pi)
plt.xlabel('Distance [m]', fontsize=12)
plt.ylabel('Phi [radians]', fontsize=12)
plt.xscale('log')
that plots this figure,
by this
fig1, ax1 = plt.subplots()
cs1 = ax1.contourf(x, y, z, 20, cmap=cmap)
fig1.colorbar(cs1,ax=ax1);
plt.xscale('log')
ax1.set_xlabel('Distance [m]', fontsize=12)
ax1.set_ylabel('Phi [radians]', fontsize=12)
#--- format y-labels in radians
y_pi = y/np.pi
unit = 0.25
y_tick = np.arange(0, 1 + unit, unit)
y_label = [r"$0$", r"$\frac{\pi}{4}$", r"$\frac{\pi}{2}$", r"$3\frac{\pi}{4}$", r"$\pi$"]
#y_label = [r"$" + format(r, ".2g")+ r"\pi$" for r in y_tick]
ax1.set_yticks(y_tick*np.pi)
ax1.set_yticklabels(y_label, fontsize=12)
#---
#--- x-labels removing the log format (i.e. 2x10^0 to 2)
ax1.set_xticks([2, 3, 4, 6, 10])
#ax1.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
#ax1.get_xaxis().get_major_formatter().labelOnlyBase = False
ax1.set_xticklabels(["2", "3", "4", "6", "10"])
plots this figure,
which tests the solutions of set ticks with logarithmic scale and prints the desired labels but without removing the default log labels format.

Matplotlib, multiple line plots axis annotation

I have five points with multiple x(t), y(t) and z(t) coordinates that I want to plot using matplotlib in one figure. I've wrote this python code:
import matplotlib.pyplot as plt
fig = plt.figure(4)
fig.set_facecolor('white')
yprops = dict(rotation=0,
horizontalalignment='right',
verticalalignment='center')
axprops = dict(yticks=[])
targets = ['centroid_label','centroid_base','centroid_apex','midgland_inferior','midgland_left','midgland_right','midgland_superior']
count = 0.0
axlist = []
for target in targets:
x,y,z = getXYZMotion_with_compensation(case,target)
ax = fig.add_axes([0.1, count, 0.8, 0.2], **axprops)
axlist.append(ax)
axprops['sharex'] = ax
axprops['sharey'] = ax
ax.plot(list_of_times_in_minutes, x)
ax.plot(list_of_times_in_minutes, y)
ax.plot(list_of_times_in_minutes, z)
ax.set_ylabel(target, **yprops)
count = count + 0.2
#turn off x ticklabels for all but the lower axes
for ax in axlist:
plt.setp(ax.get_xticklabels(), visible=False)
plt.show()
which produces:
However, I want to have x axis description for all axis below the lowest graph and y axis description for every sub-figure from -3 to 3. How can I achieve that?

Categories