У меня есть довольно длинная программа, над которой я работаю, чтобы провести анализ данных в моей лаборатории. Он берет файл csv и вычисляет предел обнаружения для одного или нескольких генов-мишеней на основе диапазона концентраций входной ДНК (фактически РНК, но в данном случае это не имеет значения).
Поскольку число оцениваемых целей является переменным, я написал две функции — одну makeplots(targets)
, которая возвращает фигуру с подграфиками (расположенными так, как я хочу, в зависимости от их количества), и массив осей для подграфиков. После некоторой обработки данных и вычислений моя функция drawplots(ax[i], x, y, [other variables for less-relevant settings])
вызывается в цикле, который перебирает массив таблиц данных для каждой цели.
makeplots()
работает нормально - все там, где я хочу, красиво оформлено и т. д. и т. д. Но как только вызывается drawplots()
, масштабы искажаются, а графики выглядят ужасно.
Приведенный ниже код не является исходным скриптом (хотя функции те же) — я вырезал большую часть шагов обработки и ввода и просто определил переменные и массивы в том виде, в каком они заканчиваются при работе с некоторыми тестовыми данными. Это только для двух целей; Я еще не пробовал с 3+, так как хочу сначала привести в порядок более простой случай.
(Простите за длинный блок импорта, я просто скопировал его из настоящего скрипта. У меня немного времени и я не хотел возиться с импортом на случай, если я удалю тот, который мне действительно все еще нужен в этом сжатом примере)
import os
import sys
import time
import math
import scipy
import datetime
import warnings
import collections
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import win32gui as wg
from win32gui import GetWindowText, GetForegroundWindow
from scipy.stats import norm
from tkinter import filedialog
from tkinter import *
actwindow = (GetForegroundWindow())
root = Tk()
root.withdraw()
cbcolors = ['#377eb8', '#f781bf', '#dede00', '#999999',
'#4daf4a', '#984ea3', '#e41a1c', '#ff7f00',
'#000000', '#a65628']
params = {'mathtext.default': 'regular'}
plt.rcParams.update(params)
#######################################################
# create figure and array of axes #
#######################################################
def makeplots(targets, active=actwindow):
numsubs = len(targets)
def rowcnt(y):
rownumb = (y//3) if y%3 == 0 else (1+(y//3))
return rownumb
def colcnt(x):
if x <= 3: colnumb = x
elif x == 4: colnumb = 2
else: colnumb = 3
return colnumb
if numsubs >= 1:
fig, axs = plt.subplots(num='LLoD', nrows=rowcnt(numsubs), ncols=colcnt(numsubs), sharey='row', figsize = [colcnt(numsubs)*5,rowcnt(numsubs)*6], subplot_kw={'adjustable': 'box', 'aspect': 1})
fig.text(0.04, 0.5, 'Probit score\n $(\sigma + 5)$', va='center', rotation='vertical', size='18')
else:
raise ValueError('Error generating plots -- number of targets must be a positive integer.')
axs = np.ravel(axs)
for i, ax in enumerate(axs):
ax.set_title(f'Limit of Detection: {targets[i]}', size=11)
ax.grid()
return fig, axs
#######################################################
# draw the actual plots #
#######################################################
def drawplots(ax, x, y, logans, color1, color2):
y95 = 6.6448536269514722
regfun = lambda m, x, b : (m*x) + b
regression = scipy.stats.linregress(x,y)
slope, intercept, r = regression.slope, regression.intercept, regression.rvalue
r2 = r**2
while True:
if logans == 'y':
x_label = '$log_{10}$(input quantity)'
break
elif logans == 'n':
x_label = 'input quantity'
break
raise ValueError('Error calling drawplots() - invalid input')
lod = (y95-intercept)/slope
xr = [0, lod*1.2]
yr = [intercept, regfun(slope, xr[1], intercept)]
regeqn = "y = " + str(f"{slope:.3f}") +"x + " + str(f"{intercept:.3f}")
ax.set_xlabel(x_label)
ax.plot(xr, yr, color=color1, linestyle='--') # plot linear regression of data
ax.plot(lod, y95, marker='o', color=color2, markersize=7) # marks the limit of detection
ax.plot(xr, [y95,y95], color=color2, linestyle=':') # horiz. line to lod
ax.plot([lod,lod], [0, 7.1], color=color2, linestyle=':') # vert. line to lod
ax.plot(x, y, color=color1, marker='x') # plot lod data points
ax.set_aspect('equal')
ax.set_xlim(left=0)
ax.plot()
return r2, lod, regeqn
#######################################################
# main script #
#######################################################
numTar = 2
logans, logconv = 'y', 'n'
targets = ['target1','target2']
qtys = np.array([6, 5, 4.7, 4, 3.7, 3, 2.7, 2.4, 2, 1.7])
prop = np.array([1, 1, 0.8, 0.2, 0.1, 0, 0, 0.1, 0.1, 0, 1,
1, 1, 1, 1, 1, 0.9, 0.8, 0.3, 0.3]).reshape(2,10)
probit = np.array([np.inf, np.inf, 5.84162123, 4.15837877, 3.71844843,
-np.inf, -np.inf, 3.71844843, 3.71844843, -np.inf,
np.inf, np.inf, np.inf, np.inf, np.inf, np.inf,
6.28155157, 5.84162123, 4.47559949, 4.47559949]).reshape(2,10)
log_qtys = np.zeros([len(qtys)])
tables = np.zeros([numTar, len(qtys), 4])
ht_collection = collections.OrderedDict()
for x, qty in enumerate(qtys):
log_qtys[x] = math.log10(qty)
for idx, tar in enumerate(targets):
tables[idx,:,0] = qtys
tables[idx,:,1] = log_qtys
for i, val in enumerate(qtys):
tables[idx,i,2] = prop[idx,i]
tables[idx,i,3] = probit[idx,i]
# this is where makeplots is called. figure, subplots, and axes
# look beautiful at this point
fig, axs = makeplots(targets)
for i, tars in enumerate(targets):
ht_collection[tars] = pd.DataFrame(tables[i,:,:], columns=["qty","log_qty","probability","probit"])
ht_collection[tars].probit.replace([np.inf, -np.inf], np.nan, inplace=True)
ht_collection[tars].dropna(inplace=True)
# this is where drawplots() is called and the figure/plots get uglified
while True:
if logans == 'y':
r2, lod, eqn = drawplots(axs[i], ht_collection[tars].log_qty, ht_collection[tars].probit, logans, cbcolors[i], cbcolors[i+5])
break
elif logans == 'n':
r2, lod, eqn = drawplots(axs[i], ht_collection[tars].qty, ht_collection[tars].probit, logans, cbcolors[i], cbcolors[i+5])
raise ValueError(f"Error calling drawplots() - subplot {i+1} of {len(targets)+1}")
if logconv == 'y': lod **=10
plt.ion()
#plt.savefig(f"{dt} LLoD Analysis at {tm}.png", format='png')
plt.show()
plt.pause(0.001)
Я хочу, чтобы подграфики оставались квадратными, поэтому, если значения x для одного подграфика попадают в диапазон [0,50], а другой — в пределах [0,2], оси x должны масштабироваться до одинаковой длины. Прикреплены «хорошая» (но пустая) цифра и «плохая» цифра (как в настоящее время выплевывается) хорошие сюжеты! плохие сюжеты!