2016-06-17 3 views
0

マイコードがgoogleドライブ(pydriveを使用)から.xlsxファイルをダウンロードし、パンダで空白のセルを見つけて空白のセルをopenpyxlで埋めます。openpyxl:いくつかの(鍵となる)ケースで空白として数式が読み取られる

openpyxl変更されたファイルを開くと、すべてが素晴らしいように見えます。しかし、pandas read_excel関数を使用すると、方程式を持つすべてのセルが空白として読み込まれます。ドライブ上のファイルをプレビューすると空白になるので、問題はopenpyxlであると思われます。 openpyxlが触れていないファイルに問題はありません。

私の問題はthis oneと非常に似ていますが、私の目的は何も入力しないままにしています(私は空白のセルを埋めるだけです)。私は本当に数式を解析する必要はありません。どのようにしてFelipe'sの修正プログラムを適用するか分かりません。

私はbokehでプロットするファイルをダウンロードできるようにしたいと思います。ユーザとPythonはどちらもプログラムを編集するので、私はパンダが方程式を読むことができるようにしたいと思います変更されたファイルまたはopenpyxlの変更されたファイル。ファイル内の方程式は「共有方程式」をクリックしてドラッグしていました。可能であればそのままにしておきたいので理想的にはdata_only=Trueを使用しないでください。私はdata_only=Falseと指定しようとしましたが、これは何も変わっていないようです。

私はopenpyxlを使用しています。 2.3.5 2.4と、コード実行中にExcelを閉じたままにしています。

openpyxl変更前後のファイルのバージョンはavailable hereです。

私のコードは、すべてのopenpyxlコードがに隔離され、ここにある: #インポートライブラリ インポート日時 輸入IMP 輸入OS itertoolsはボケのため #相対輸入isliceインポートからopenpyxl輸入load_workbook からPD として 輸入パンダ対話

dl = imp.load_source('downloader', os.getcwd() + 
         '/Project/downloader.py') 
gdu = imp.load_source('googledriveutils', os.getcwd() + 
         '/Project/googledriveutils.py') 
remove_file = gdu.remove_file 
find_folderid = gdu.find_folderid 
get_file_list = gdu.get_file_list 


# Define constants 
COL_LABEL = '\nProbe - ' 
# TODO: ORP PROBE: REVISE THIS DATE when orp probe is added 
IGNORE_BEFORE = pd.to_datetime('5.24.2016') 
PROBE_DICT = {'DO (mg/L)': 'DO mg/L', 
       'pH': 'pH', 
       'NH4+ (mgN/L)': 'Ammonium', 
       'ORP (mV)': 'ORP mV'} 
TS = '\nTimestamps' 


def save_to_workbook(newval, 
        date, 
        header, 
        rows_to_skip=12, 
        wbname='temp.xlsx', 
        sheet_name='Reactor Data'): 
    wb = load_workbook(wbname) 
    ws = wb[sheet_name] 
    for cell in ws[rows_to_skip+1]: 
     # TODO: Error if header isn't found 
     if cell.value == header: 
      colno = cell.col_idx 
      break 

    for row in ws.iter_rows(min_row=rows_to_skip+1, min_col=1, max_col=1): 
     for cell in row: 
     # TODO: Error if date isn't found 
      if cell.value == date: 
       rowno = cell.row 
       break 

    ws.cell(row=rowno, column=colno).value = newval 
    wb.save(wbname) 


    return df 





def find_r1masterfile(): 
    # Navigate through the directories 
    wlab_fid = find_folderid('Winkler Lab', 'root') 
    kp_fid = find_folderid('KathrynsProjects', wlab_fid) 
    amxrct_fid = find_folderid('Anammox Reactor', kp_fid) 
    trials_fid = find_folderid('Reactor Trials', amxrct_fid) 
    # List files in directory 
    file_list = get_file_list(trials_fid) 
    for afile in file_list: 
     if afile['title'] == 'AMX RCT.xlsx': 
      # Return the file we asked for 
       return afile 
     # TODO: error if there was no file with that name 


def save_r1masterfile(csv, rows_to_skip=12, filename='temp.xlsx', sheet_name='Reactor Data'): 
    # Get the file we want 
    master_file = find_r1masterfile() 
    try: 
     master_file.GetContentFile(filename) 
    except Exception, e: 
     print "Warning: Something wrong with file R1 Master File." 
     print str(e) 
     # TODO: add an email alarm to responsible user 

    if csv: 
     return master_file 
    else: 
     # convert to dataframe 
     wb = load_workbook(filename, data_only=True) 
     ws = wb[sheet_name] 
     print ws["B14"].value 
     data = ws.values 
     data = list(data)[rows_to_skip:] 
     cols = list(data[0]) 
     del cols[0] 
     del data[0] 
     idx = [r[0] for r in data] 
     data = (islice(r, 1, None) for r in data) 
     df = pd.DataFrame(data, index=idx, columns=cols) 
     print df.dropna(how='all') 
     remove_file(filename) 
     return df 


def upload_r1masterfile(filename='temp.xlsx'): 
    # Get the file we want 
    master_file = find_r1masterfile() 
    try: 
     master_file.SetContentFile(filename) 
     master_file.Upload() 
    except Exception, e: 
     print "Warning: Something wrong with file R1 Master File." 
     print str(e) 
     # TODO: add an email alarm to responsible user 


def populate_r1masterfile(rows_to_skip=12, filename='temp.xlsx'): 
    # Get the R1 master file as a file 
    save_r1masterfile(True) 
    # Convert the juicy stuff to a dataframe 
    masterdf = pd.read_excel(filename, 
          sheetname='Reactor Data', 
          encoding="utf-16", 
          skiprows=rows_to_skip, 
          sep='\t', 
          index_col='Date', 
          keep_default_na=False, 
          na_values=['-1.#IND', '1.#QNAN', '1.#IND', 
          '-1.#QNAN', '','N/A', '#NA', 'NA' 
          'NULL', 'NaN', '-NaN', 'nan', '-nan']) 
    # Find what we will populate with probe data 
    # Find timestamps 
    ts_columns = [col for col in masterdf.columns if TS in col] 
    tsdf = masterdf[ts_columns] 
    # Find probes, ignore before given date 
    probe_columns = [col for col in masterdf.columns if COL_LABEL in col] 
    probedf = masterdf[probe_columns] 
    probedf = probedf[masterdf.index > IGNORE_BEFORE] 
    # Find Indices and column labels of blank values 
    stackdf = probedf.stack(dropna=False) 
    empty = stackdf[stackdf.isnull()].index.tolist() 

    # For each blank look for the probe, time & date of cycle, and return val 
    for each in empty: 
     probe, time = each[1].split(COL_LABEL) 
     time = tsdf.loc[each[0], time+TS] 
     ts = each[0]+pd.DateOffset(hour=time.hour, minute=time.minute) 
     val = dl.get_val_from(1, ts, PROBE_DICT.get(probe)) 
     probedf.set_value(each[0], each[1], val) 
     # Save that value to the workbook 
     save_to_workbook(val, each[0], each[1]) 
    upload_r1masterfile() 
    print 'Master file updated. ' + str(datetime.datetime.now()) 
    remove_file('temp.xlsx') 
    return probedf 

UPDATE

私はチャーリーのSUごとに私のコードを修正ggestions(上記アップデート)しかし、私はまだデータフレームでNonesを取得しています。より具体的な例を提供するために、なぜそれは私がこのコードを実行すると次のとおりです。this file

from openpyxl import load_workbook 

wb = load_workbook('AMX RCT mod.xlsx', data_only=True) 
ws = wb['Reactor Data'] 
print 'Value of B14 Formula is: ' + str(ws["B14"].value) 

を、私は戻って?:

Value of B14 Formula is: None 

を取得するには、回避策はありますか?

+0

具体的な例と、おそらくサンプルファイルを提供できますか? 2.3には、Felipeの数式変換コードが含まれています。しかし、もしあなたがパンダと仕事をしたいなら、あなたは2.4を試して、ワークシートからデータフレームにまっすぐ進むことができます。 –

答えて

1

openpyxl 2.4を使用すると、1回のパスで必要な作業を行うことができます。私はあなたの最初の機能を取ってそれを適応させました。

from itertools import islice 
from pandas import DataFrame 

def save_to_workbook(newval, 
        date, 
        header, 
        rows_to_skip=12, 
        wbname='temp.xlsx', 
        sheet_name='Reactor Data'): 
    wb = load_workbook(wbname) 
    ws = wb[sheet_name] 
    rowno = None 
    colno = None 
    for cell in ws[1]: 
     # TODO: Error if header isn't found 
     if cell.value == header: 
      colno = col 

    for row in ws.iter_rows(min_row=rows_to_skip+1, min_col=1, max_col=1): 
     for cell in row: 
     # TODO: Error if date isn't found 
      if cell.value == date: 
       rowno = row 
       break 

    # TODO: Fix this 
    ws.cell(row=rowno, column=colno).value = newval 

    # convert to dataframe 
    data = ws.values 
    cols = next(data)[1:] 
    data = list(data) 
    idx = [r[0] for r in data] 
    data = (islice(r, 1, None) for r in data) 
    df = DataFrame(data, index=idx, columns=cols) 

    return df 

これはおそらくあなたが望むすべてのことをするわけではありませんが、うまくいけばあなたを始められます。また、ワークブック全体を保存して解析するのを避けることができます。

openpyxl 2.4を使用するには、pip install -U --pre openpyxlを実行するか、チェックアウトを行う必要があります。

openpyxlとpandasを併用する方法の詳細については、documentationを参照してください。mailing listから

+0

こんにちはチャーリー!あなたのお返事をありがとうございました。これは私のコードを構造化するいくつかの良い方法を考えてくれました。しかし、私は数式を使って値を求めるとき、私は 'なし'です。それ以上のヒント? –

+0

あなたは「数式で値を求めていますか?」私はこれがメーリングリストとファイルを提供できるかどうかを理解することを推奨します。 –

+0

メーリングリストへの送信。わかりやすくするために、「ファイルを提供する」と言うと、私の.pyファイルまたは私の.xlsxファイルを意味しますか? –

0

チャーリーの回答:あなたは数式を保持したい場合は

だから、その後、あなただけのモードのデータを使用してはなりません。
先に述べたように、あなたがA3の値を知っている
したい場合なエクセル
やOpenOfficeのようなアプリケーションにファイルを渡す必要がありますので、openpyxlは式を評価しません - あなたはこの種のもののためにOpenOfficeのヘッドレスを実行することができますか
xlwingsをExcel用に使用すると、数式の評価が行われます。
このファイルをデータ専用モードで読み込んで、計算結果を確認することができます。
また、PyCelのようなものを使って
評価を行うこともできます。しかし、基本的に計算を行いたい場合は、
をPythonで実行します。

私の回避策は、すべての計算をExcelファイルで行われるように列ごとにやり直すことでした。 I. Excelのこのようなファイル:

 col1 col2 col3 col4 
row1 1 3  =A1+B1 =1+3 
row2 2 4  =A2+B2 =2+4 

を私はこのようなデータフレーム(文字列として方程式を維持するために)としてインポート:

wb = load_workbook(filename, data_only=False) 
ws = wb[sheet_name] 
data = ws.values 
cols = next(data)[1:] 
data = list(data) 
idx = [r[0] for r in data] 
data = (islice(r, 1, None) for r in data) 
df = DataFrame(data, index=idx, columns=cols) 

そして、次の操作を行います

parse_excel = lambda x: eval(str(x)[1:]) if isinstance(x, str) else x 
for col in df.columns: 
    try: 
     df[col] = df[col].map(parse_excel) 
    except: 
     pass 
df['col3'] = df['col2']+df['col1'] 

私はこれが多分これを行う最もやっかいな方法だと確信していますが、今のところうまくいきます。

関連する問題