Skip to content

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

Open
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions