Exemple #1
0
    /// <summary>
    /// Load a file path into a DataVariable. Does NOT add it to the DataManager
    /// </summary>
    /// <param name="hasRowHeaders">Flag. Set if data file is expected to have row headers.</param>
    /// <param name="hasColumnHeaders">Flag. Set if data file is expected to have column headers.</param>
    /// <param name="dataVariable">Returns a new DataVariable. Is valid but empty object if error or canceled.</param>
    /// <param name="errorMsg">Contains an error message on failure.</param>
    /// <returns>True on success. False if user cancels file picker or if there's an error.</returns>
    public bool LoadFile(string path, bool hasRowHeaders, bool hasColumnHeaders, out DataVariable dataVariable, out string errorMsg)
    {
        dataVariable = new DataVariable();

        //foreach (string s in path)
        //    Debug.Log(s);

        bool success = false;

        errorMsg = "No Error";

        //Cast to base class for reading in the file
        CSVReaderData data = (CSVReaderData)dataVariable; // new CSVReaderData();

        try
        {
            success = CSVReader.Read(path, hasColumnHeaders, hasRowHeaders, ref data, out errorMsg);
        }
        catch (Exception e)
        {
            errorMsg = "Exception caught: " + e.ToString();
            Debug.Log(errorMsg);
            return(false);
        }
        if (success)
        {
            dataVariable.Filepath = path;
        }
        else
        {
            Debug.Log("Error msg from csv read: \n");
            Debug.Log(errorMsg);
        }
        return(success);
    }
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.O))
        {
            string[] paths = StandaloneFileBrowser.OpenFilePanel("Open File", "", "", true);
            foreach (string s in paths)
            {
                Debug.Log(s);
            }
            if (paths.Length == 0)
            {
                return;
            }

            bool   success  = false;
            string errorMsg = "Unknown Error";
            //CSVReaderData data = new CSVReaderData();
            DataVariable  dataVariable = new DataVariable();
            CSVReaderData dataObj      = (CSVReaderData)dataVariable; // new CSVReaderData();
            try
            {
                success = CSVReader.Read(paths[0], hasColumnsHeader, hasRowHeader, ref dataObj, out errorMsg);
            }
            catch (Exception e)
            {
                Debug.Log("Exception caugt: " + e.ToString());
                return;
            }
            if (!success)
            {
                Debug.Log("Error msg from csv read: ");
                Debug.Log(errorMsg);
            }
            else
            {
                dataVariable.DumpMetaData();
                dataVariable.DumpData();
                dataVariable.Clear();
            }
        }
    }
Exemple #3
0
    /// <summary>
    /// Read the csv or tab-delimited file specified by 'file'.
    /// </summary>
    /// <param name="file">Full path for file to read.</param>
    /// <param name="columnHeadersExpected">Flag. Set this if columns headers are expected in the file. This is headers in the first row/line of the file.</param>
    /// <param name="rowHeadersExpected">Flag. Set this is row headers are expected. This means the first field/column of each row is a header/name/string for the row</param>
    /// <param name="result">Ref var. If passed object is non-null, it's filled, otherwise a new data object - containing data, headers, etc.</param>
    /// <param name="errorMsg">Return value. Error message string if failed (including exception string if an excpetion occured).</param>
    /// <returns>True on success, otherwise false</returns>
    public static bool Read(string file, bool columnHeadersExpected, bool rowHeadersExpected, ref CSVReaderData result, out string errorMsg)
    {
        errorMsg = "no error";

        //For matching no data - NaN and None. This list (initially at least) from what python recognizes according to https://stackoverflow.com/questions/46612576/counting-number-of-nan-not-zeros-or-blanks-in-csv
        //NOTE - we'll do a case insensitive comparison
        string[] noDataStrings = new string[] { "none", "#N/A", "#N/A N/A", "#NA", "-1.#IND", "-1.#QNAN", "-nan", "1.#IND", "1.#QNAN", "N/A", "NA", "NULL", "nan" };

        if (result == null)
        {
            result = new CSVReaderData();
        }

        //var list = new List<Dictionary<string, object>>();
        //TextAsset textData = Resources.Load(file) as TextAsset;
        //string[] lines = Regex.Split(textData.text, LINE_SPLIT_RE);

        //NOTE - reads whole file into memory. If we get into big data, we'll want
        // to read line-by-line. See https://stackoverflow.com/questions/46405067/reading-a-file-line-by-line-in-c-sharp-using-streamreader
        //NOTE - will this work with non-windows line endings?
        string[] lines;
        try
        {
            //NOTE - reads in all lines at once. Won't be good for very large files.
            lines = File.ReadAllLines(file);
        }
        catch (Exception e)
        {
            errorMsg = "Failed loading file: " + file + ".  Exception: " + e.ToString();
            Debug.Log(errorMsg);
            result.Clear();
            return(false);
        }

        if (lines.Length < 1)
        {
            result.Clear();
            return(false);
        }

        int numDataColumns = 0;
        int numDataRows    = 0;

        result.hasRowHeaders    = rowHeadersExpected;
        result.hasColumnHeaders = columnHeadersExpected;

        //number of data rows
        result.numDataRows = numDataRows = lines.Length - (columnHeadersExpected ? 1 : 0);

        //number of data columns and columns headers
        var firstRow      = Regex.Split(lines[0], SPLIT_RE);
        int numAllColumns = firstRow.Length;

        if (columnHeadersExpected)
        {
            //If we have row headers, skip the first value since it's not a data-column header
            int ind = rowHeadersExpected ? 1 : 0;
            for (int i = ind; i < firstRow.Length; i++)
            {
                result.columnHeaders.Add(firstRow[i]);
            }
        }
        result.numDataCols = numDataColumns = firstRow.Length - (rowHeadersExpected ? 1 : 0);

        //Alloc the data array
        try
        {
            result.Data = new float[numDataRows][];
            for (int row = 0; row < numDataRows; row++)
            {
                result.Data[row] = new float[numDataColumns];
            }
        }
        catch (Exception e)
        {
            errorMsg = "Aborting. Failed allocating data array, with exception: " + e.ToString();
            Debug.Log(errorMsg);
            result.Clear();
            return(false);
        }

        //Parse the data lines
        int start = columnHeadersExpected ? 1 : 0;

        for (var fileRow = start; fileRow < lines.Length; fileRow++)
        {
            var values = Regex.Split(lines[fileRow], SPLIT_RE);
            //or try string.split for simpler: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/parse-strings-using-split

            //Empty line or not enough columns? Abort.
            if (values.Length != numAllColumns)
            {
                errorMsg = "Row " + fileRow + " is empty or otherwise incorrect length: " + values.Length + " instead of " + numAllColumns + ". Aborting.";
                Debug.Log(errorMsg);
                result.Clear();
                return(false);
            }

            //Parse a line
            for (var fileCol = 0; fileCol < numAllColumns; fileCol++)
            {
                string value = values[fileCol];
                int    ii    = fileRow - (columnHeadersExpected ? 1 : 0);
                int    jj    = fileCol - (rowHeadersExpected ? 1 : 0);

                //empty data cell? Call it NaN if we're not expecting row or columns headers, or we're past the first column
                if (value == "" && ((rowHeadersExpected && fileCol > 0) || !rowHeadersExpected || !columnHeadersExpected))
                {
                    /* were not supporting NaN originally
                     * errorMsg = "Empty data cell. Row, col: " + fileRow + ", " + fileCol + ". Aborting.";
                     * Debug.Log(errorMsg);
                     * result.Clear();
                     * return false;
                     */
                    result.Data[ii][jj] = float.NaN;
                    continue;
                }
                //Trim chars in TRIM_CHARS, remove trailing and leading white space, replace \
                value = value.Trim(TRIM_CHARS).Trim().Replace("\\", "");
                if (rowHeadersExpected && fileCol == 0)
                {
                    //Header
                    result.rowHeaders.Add(value);
                    continue;
                }

                //data
                float f;
                if (float.TryParse(value, out f))
                {
                    result.Data[ii][jj] = f;
                }
                else
                {
                    //first check for NaN or None (note that "NaN" may be parsed by TryParse above)
                    bool foundNaN = false;
                    foreach (string s in noDataStrings)
                    {
                        if (value.Equals(s, StringComparison.CurrentCultureIgnoreCase))
                        {
                            result.Data[ii][jj] = float.NaN;
                            foundNaN            = true;
                            break;
                        }
                    }
                    if (foundNaN)
                    {
                        continue;
                    }

                    //error
                    string ex = "";
                    if (fileRow == 0 && !columnHeadersExpected)
                    {
                        ex = "Wasn't expecting first row to be headers. But is it maybe? ";
                    }
                    else if (fileCol == 0 && !rowHeadersExpected)
                    {
                        ex = "Wasn't expecting first columns to be headers. But is it maybe? ";
                    }
                    errorMsg = ex + "Expected a number but got non-numeric value '" + value + "', at row, col: " + fileRow + ", " + fileCol + ". Aborting.";
                    Debug.Log(errorMsg);
                    result.Clear();
                    return(false);
                }
            }
        }
        return(true);
    }