Skip to content

Type Narrowing an object which is either dfd.Series or dfd.DataFrame to dfd.DataFrame #640

@bml1g12

Description

@bml1g12

Is your feature request related to a problem? Please describe.

I am unclear on the recommended way of type narrowing a dfd.Series ❘ dfd.DataFrame object to a dfd.DataFrame

Describe the solution you'd like

e.g. this should work, or some other approach that achieves the type narrowing

  if (!(multiMetricDf instanceof dfd.DataFrame)) {
    throw new Error(
      `Expected a DataFrame here but got ${multiMetricDf.constructor.name}`,
    )
  }

The above code snippet does not work as it can log " "Expected a DataFrame here but got DataFrame"" i.e. false positive, and I would like a solution like this to type narrow

Describe alternatives you've considered

const dfd = require("danfojs-node");

const json_data = [
  { A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
  { A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
  { A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
  { A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 },
];

const df = new dfd.DataFrame(json_data)
const multiMetricDf = dfd.concat({
  dfList: [df, df],
  axis: 0,
})
multiMetricDf instanceof dfd.DataFrame // returns False

The above code snippet returns False

If there was a method to convert Series to DataFrame (#619) that would be a suitable workaround

Additional context

For working with Danfo, I think such type narrowing is essential

const dfd = require("danfojs-node");


function logPrototypeNames(obj: any): void {
  let proto = Object.getPrototypeOf(obj);

  while (proto) {
      console.log(`Prototype constructor name: ${proto.constructor.name}`);
      proto = Object.getPrototypeOf(proto);
  }
}

const json_data = [
  { A: 0.4612, B: 4.28283, C: -1.509, D: -1.1352 },
  { A: 0.5112, B: -0.22863, C: -3.39059, D: 1.1632 },
  { A: 0.6911, B: -0.82863, C: -1.5059, D: 2.1352 },
  { A: 0.4692, B: -1.28863, C: 4.5059, D: 4.1632 },
];
const df = new dfd.DataFrame(json_data)

console.log("df is instance of DataFrame:", df instanceof dfd.DataFrame);

logPrototypeNames(df);
console.log()

const multiMetricDf = dfd.concat({
  dfList: [df, df],
  axis: 0,
})
multiMetricDf instanceof dfd.DataFrame

console.log("multiMetricDf is NOT instance of DataFrame:", multiMetricDf instanceof dfd.DataFrame);

logPrototypeNames(multiMetricDf);

console.log("here", multiMetricDf.ctypes)

Returns

df is instance of DataFrame: true
Prototype constructor name: DataFrame
Prototype constructor name: DataFrame
Prototype constructor name: NDframe
Prototype constructor name: Object

multiMetricDf is NOT instance of DataFrame: false
Prototype constructor name: DataFrame
Prototype constructor name: NDframe
Prototype constructor name: Object

So not sure what the problem is here.

This is my current workaround:

/**
 * Allows type narrowing of Series to DataFrame
 * https://github.com/javascriptdata/danfojs/issues/640
 *
 * @param df - DataFrame or Series
 * @returns True if it has a ctypes attribute, expected on DataFrame but not Series
 */
function isDataFrame(df: unknown): df is dfd.DataFrame {
  if (df instanceof dfd.Series) {
    return false
  }
  if ((df as dfd.DataFrame).ctypes !== undefined) {
    // ctypes attribute only exists on DataFrame
    return true
  } else {
    return false
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions