Загружать только сегмент текстового файла, используя numpy и itertools - PullRequest
1 голос
/ 19 февраля 2020

У меня есть фрагмент кода, который первоначально декодирует файл .dat в файл .txt, используя двоичный декодер цикла. В результате получается более 500 строк текстового файла точек данных со строками 0–65, представляющими заголовки и другие функции отображения, а последние несколько строк, начиная с 586, представляют собой неправильно декодированный текст, который выглядит примерно так:

ßÅBÎheÀœaÜ; sî3TÐêM · Zì? pêI † Q '& × ¥ ü # ÇPËiPì¿j – hñHžíoî # ˆ [ÿ> Bÿà @ ÌhcP¿_ÔkõOˆEñlÀ ‹J–> tò5Ægã_ð ° Ù}}}} 44} ž 4} 4 4 4 ž ž 4 ž ž 4 ž ž 4 4 4 ž ž ž ž ž ž 4 ž 4 ž ž 4 ž 4 ž ž 4 4 4 ž 4 4 ž ž ž 4 ž ž ž 4 ž ž ž ž 4 4 ž ž ž ž ž 4 ž ž ž ž ž 4 HlHí - '/ mÑ = tt k × £ QÉoû ·] Ý & õC´Jœ9mû »Zà +] þ6ƒ [‰ ¶ ¶S; Uö ¥ Wã Lè: ÂXÿ4sÈÄAïPó € D $ EØ d • dГ eïkHâN Ò Ò C Ò Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ñ Ò Ñ Ò? Æ Ñ] ô †} ÌdDñË, WÎÄdó ^ ã8žDäÓ) Çq9} ùÃfÄP ÷ ÇzîoiÒ ÁpìeSÖ € ÒMŒÀ «; Bö

Я использую код:

with open (file) as f:  
    xpoints, ypoints, gradient = np.loadtxt(itertools.islice(f,68, 584), delimiter=',', unpack=True)

1009 загружать только те строки, которые содержат точки данных, которые мне нужны.

По какой-то причине, однако, это приводит к тому, что программа выдает ошибку, из-за которой не может декодировать байт, поскольку он отображается в неопределенное значение. Я подтвердил, что это вызвано нежелательным текстом на б Внизу и, кажется, выброшено в строке, показанной выше, но я не могу понять, почему это так, поскольку вообще не нужно читать эти строки.

Полная ошибка:

Файл "C: \ Users \ brady \ Desktop \ Slider_All \ Slide-Mobile.py", строка 57, в модуле

xpoints, ypoints, градиент = np.loadtxt (IT.islice (f , 68, 500), delimiter = ',', unpack = True) Файл "C: \ Users \ brady \ AppData \ Local \ Programs \ Python \ Python38-32 \ lib \ site-packag es \ numpy \ lib \ npyio.py ", строка 1159, в loadtxt для x в read_data (_loadtxt_chunksize): файл" C: \ Users \ brady \ AppData \ Local \ Programs \ Python \ Python38-32 \ lib \ site-packag es \ numpy \ lib \ npyio.py ", строка 1075, в read_data для i, строка в перечислении (line_iter): Файл" C: \ Users \ brady \ AppData \ Local \ Programs \ Python \ Python38-32 \ lib \ encodings \ c p1252.py ", строка 23, в декодировании возвращает codecs.charmap_decode (input, self.errors, decoding_table) [0] UnicodeDecodeError: код 'charmap' c не может декодировать байт 0x81 в позиции 7758: преобразователь cha отображается в undef ined

Может ли itertools.islice или numpy.loadtxt пытаться сначала прочитать весь документ, прежде чем он возьмет фрагмент и столкнется с проблемой, или это что-то еще, чего я полностью упускаю. Я опубликую весь свой неотредактированный код ниже для завершения, спасибо за любую помощь.

import matplotlib.animation as animation
from matplotlib.widgets import Slider, Button
import matplotlib as mpl
from matplotlib import pyplot as plt
import scipy.interpolate as inter
import numpy as np
import itertools as IT
from itertools import cycle
from scipy.interpolate import interp1d
import os


file = 'example.dat'
x1 = 250    #Lower bound    Bigger bound leads to lots of lag
x2 = 300    #Upper bound    Recommended to remain close to range of 50

#=========================================================================================================================
start = []  #Stores data before given points
end = []    #Stores data after given points
files = []  #Stores text file to be removed when done

#This function decodes and re-encodes the dat files 
class Decoder:
    def decode(fn_in, fn_out):
        CIPHER = cycle([0b01011100, 0b00100111, 0b10111010, 0b01111011, 0b11110010, 0b00110010, 0b10100101])
        with open(fn_in, 'rb') as fin, open(fn_out, 'wb') as fout:        
            fout.write(fin.read(14))
            byte = fin.read(1)
            while byte:
                fout.write( ( int.from_bytes(byte, 'big') ^ next(CIPHER) ).to_bytes(1, 'big') )
                byte = fin.read(1)

    def to_txt(filename):
        #global files
        if filename [-3:] == "dat":        
            Decoder.decode( filename, filename[:-3] + "txt" )
            filename = filename[:-3] + "txt"    
        else:
            print("Extension not recognised for input filename \""+str(filename)+"\", skipping...")

        return filename

    def to_dat(filename):
        files.append(filename)
        if filename [-3:] == "txt":    
                Decoder.decode( filename, tempfile[:-3]+ "dat" )   
                #file.append(filename[:-3] + "dat")      
        else:
            print("Extension not recognised for input filename \""+str(filename)+"\", skipping...")

if file[-3:] == "dat":
    file = Decoder.to_txt(file) #Converts .dat to .txt
    files.append(file)

#Gets all data points from file
with open (file) as f:  
    xpoints, ypoints, gradient = np.loadtxt(IT.islice(f,68, 584), delimiter=',', unpack=True)


#get a list of points to fit a spline to as well
xmin = min(xpoints) 
xmax = max(xpoints) 

#Calculates which lines of data are required to plot
X1 = int(516*((x1 - xmin)/(xmax-xmin))) + 68
X2 = int(516*((x2 - xmin)/(xmax-xmin))) + 68

#Gets specific lines and saves the rest to copy back later
with open (file) as f:
    xp, ypoints, gradient = np.loadtxt(IT.islice(f,X1, X2), delimiter=',', unpack=True)
with open(file) as f:
    for line in IT.islice(f,0,X1):
        start.append(line)
with open (file) as f:
    for line in IT.islice(f,X2,584):
        end.append(line)

#Sets amount of data points to plot, must be multiple of point range
#The lower the number the more accurate the plot but the slower it will run 
N = len(xp)

if N < 200:
    j = 1                   
elif N < 400:
    j = 1
else: j = 1 

x = xp[::j]
yvals = ypoints[::j]
N = len(x)
xnew = xp

#spline fit
spline = inter.InterpolatedUnivariateSpline (x, yvals)

#set up a plot
fig,axes = plt.subplots(1,1,figsize=(12.0,4.0),sharex=True)
fig,axes.set_position([0.05,0.08,0.93,0.80])
ax1 = axes

pind = None #active point
epsilon = 5 #max pixel distance
#Updates plot when point is dragged
def update(val):
    global yvals
    global spline
    # update curve
    for i in np.arange(N):
      yvals[i] = sliders[i].val 
    l.set_ydata(yvals)
    spline = inter.InterpolatedUnivariateSpline (x, yvals)
    m.set_ydata(spline(X))
    # redraw canvas while idle
    fig.canvas.draw_idle()

#Resets plot back to original save from when opened
def reset(event):
    global yvals
    global spline
    #reset the values
    yvals = ypoints
    for i in np.arange(N):
      sliders[i].reset()
    spline = inter.InterpolatedUnivariateSpline (x, yvals)
    l.set_ydata(yvals)
    m.set_ydata(spline(X))
    # redraw canvas while idle
    fig.canvas.draw_idle()

#Overwirtes current save with new plot
def save(event):
    f = interp1d(x, yvals, kind='cubic')
    ynew = f(xnew)
    ax1.plot(xnew,ynew)

    newfile = np.vstack((xnew,ynew, gradient)).T

    with open(file, 'w') as f:
        for item in start:
            f.write("%s" % item)
        np.savetxt(f, newfile, delimiter = ',')
        for item in end:
            f.write("%s" % item)
        #f.write('""')
    Decoder.to_dat(file) #Converts .txt to .dat

#Event handler for mouse click
def button_press_callback(event):
    'whenever a mouse button is pressed'
    global pind
    if event.inaxes is None:
        return
    if event.button != 1:
        return
    #print(pind)
    pind = get_ind_under_point(event)    

#Event handler for mouse release
def button_release_callback(event):
    'whenever a mouse button is released'
    global pind
    if event.button != 1:
        return
    pind = None

#Gets clicked point number
def get_ind_under_point(event):
    'get the index of the vertex under point if within epsilon tolerance'

    # display coords
    #print('display x is: {0}; display y is: {1}'.format(event.x,event.y))
    t = ax1.transData.inverted()
    tinv = ax1.transData 
    xy = t.transform([event.x,event.y])
    #print('data x is: {0}; data y is: {1}'.format(xy[0],xy[1]))
    xr = np.reshape(x,(np.shape(x)[0],1))
    yr = np.reshape(yvals,(np.shape(yvals)[0],1))
    xy_vals = np.append(xr,yr,1)
    xyt = tinv.transform(xy_vals)
    xt, yt = xyt[:, 0], xyt[:, 1]
    d = np.hypot(xt - event.x, yt - event.y)
    indseq, = np.nonzero(d == d.min())
    ind = indseq[0]

    #print(d[ind])
    if d[ind] >= epsilon:
        ind = None

    #print(ind)
    return ind

#Event handler for mosue movement
def motion_notify_callback(event):
    'on mouse movement'
    global yvals
    if pind is None:
        return
    if event.inaxes is None:
        return
    if event.button != 1:
        return

    #update yvals
    #print('motion x: {0}; y: {1}'.format(event.xdata,event.ydata))
    yvals[pind] = event.ydata 

    # update curve via sliders and draw
    sliders[pind].set_val(yvals[pind])
    fig.canvas.draw_idle()



X = xp
ax1.plot (X, ypoints, 'k--', label='original')
l, = ax1.plot (x,yvals,color='k',linestyle='none',marker='o',markersize=8)
m, = ax1.plot (X, spline(X), 'r-', label='spline')

if max(ypoints) > 0:
    yheight = 0.01*max(ypoints)
    ylower =0
else: 
    yheight = -0.1*max(ypoints)
    ylower = yheight    

ax1.set_yscale('linear')
ax1.set_xlim(x1, x2)
ax1.set_ylim(min(ypoints)-ylower,max(ypoints)+yheight)
ax1.grid(True)
ax1.yaxis.grid(True,which='minor',linestyle='--')


sliders = []

for i in np.arange(N):

    axamp = plt.axes([0.84, -1, 0.12, 0.01])
    # Slider
    s = Slider(axamp, 'p{0}'.format(i), -100, 10, valinit=yvals[i])
    sliders.append(s)


for i in np.arange(N):
    #samp.on_changed(update_slider)
    sliders[i].on_changed(update)

axres = plt.axes([0.84, 0.90, 0.15, 0.08])
bres = Button(axres, 'Reset')
bres.on_clicked(reset)

axsave = plt.axes([0.68, 0.90, 0.15, 0.08])
bsave = Button(axsave, 'Save')
bsave.on_clicked(save)


fig.canvas.mpl_connect('button_press_event', button_press_callback)
fig.canvas.mpl_connect('button_release_event', button_release_callback)
fig.canvas.mpl_connect('motion_notify_event', motion_notify_callback)

plt.show()
for filename in files:
    os.remove(filename)

РЕДАКТИРОВАТЬ: я знаю, что ошибка почти наверняка связана с командой itertools.islice, так как я нашел похожая проблема здесь: Python 3 itertools.islice продолжаются, несмотря на UnicodeDecodeError .
В настоящее время изучается альтернативный способ потенциального открытия файла, поскольку изменение стиля декодирования для .dat на данном этапе невозможно

1 Ответ

0 голосов
/ 19 февраля 2020

Я решил проблему, используя решение, опубликованное здесь: { ссылка }

Мой окончательный код:

types_of_encoding = ["utf8", "cp1252"]
for encoding_type in types_of_encoding:
    with open (file, 'r', encoding = encoding_type, errors='ignore') as f:
        xpoints, ypoints, gradient = np.loadtxt(IT.islice(f,65, 582), delimiter=',', unpack=True)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...