Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ val modulesUsingJava11 = with(projects) {
dataframeGeoJupyter,
examples.ideaExamples.titanic,
examples.ideaExamples.unsupportedDataSources,
samples,
// samples,
plugins.dataframeGradlePlugin,
)
}.map { it.path }
Expand Down
43 changes: 32 additions & 11 deletions core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -2232,11 +2232,23 @@ public final class org/jetbrains/kotlinx/dataframe/api/ForEachKt {
}

public final class org/jetbrains/kotlinx/dataframe/api/FormatClause {
public fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/kotlinx/dataframe/api/FormatHeaderKt {
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/DataFrame;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/DataFrame;[Ljava/lang/String;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/DataFrame;[Lkotlin/reflect/KProperty;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/DataFrame;[Lorg/jetbrains/kotlinx/dataframe/columns/ColumnReference;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/api/FormattedFrame;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/api/FormattedFrame;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun formatHeader (Lorg/jetbrains/kotlinx/dataframe/api/FormattedFrame;[Ljava/lang/String;)Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;
public static final fun with (Lorg/jetbrains/kotlinx/dataframe/api/HeaderFormatClause;Lkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/api/FormattedFrame;
}

public final class org/jetbrains/kotlinx/dataframe/api/FormatKt {
public static final fun and (Lorg/jetbrains/kotlinx/dataframe/api/CellAttributes;Lorg/jetbrains/kotlinx/dataframe/api/CellAttributes;)Lorg/jetbrains/kotlinx/dataframe/api/CellAttributes;
public static final fun at (Lorg/jetbrains/kotlinx/dataframe/api/FormatClause;Ljava/util/Collection;)Lorg/jetbrains/kotlinx/dataframe/api/FormatClause;
Expand All @@ -2259,8 +2271,8 @@ public final class org/jetbrains/kotlinx/dataframe/api/FormatKt {
}

public final class org/jetbrains/kotlinx/dataframe/api/FormattedFrame {
public fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function3;)V
public synthetic fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getDisplayConfiguration (Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;)Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;
public final fun toHtml (Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;)Lorg/jetbrains/kotlinx/dataframe/io/DataFrameHtmlData;
public static synthetic fun toHtml$default (Lorg/jetbrains/kotlinx/dataframe/api/FormattedFrame;Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;ILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/io/DataFrameHtmlData;
Expand Down Expand Up @@ -2545,6 +2557,12 @@ public final class org/jetbrains/kotlinx/dataframe/api/HeadKt {
public static synthetic fun head$default (Lorg/jetbrains/kotlinx/dataframe/DataFrame;IILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/DataFrame;
}

public final class org/jetbrains/kotlinx/dataframe/api/HeaderFormatClause {
public fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)V
public synthetic fun <init> (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/kotlinx/dataframe/api/ImplodeKt {
public static final fun implode (Lorg/jetbrains/kotlinx/dataframe/DataFrame;Z)Lorg/jetbrains/kotlinx/dataframe/DataRow;
public static final fun implode (Lorg/jetbrains/kotlinx/dataframe/DataFrame;ZLkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/DataFrame;
Expand Down Expand Up @@ -6194,25 +6212,27 @@ public final class org/jetbrains/kotlinx/dataframe/io/DataFrameHtmlData$Companio

public final class org/jetbrains/kotlinx/dataframe/io/DisplayConfiguration {
public static final field Companion Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration$Companion;
public synthetic fun <init> (Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Ljava/lang/String;ZZZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Ljava/lang/String;ZZZZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Ljava/lang/String;ZZZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Ljava/lang/String;ZZZZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Integer;
public final fun component10 ()Z
public final fun component11 ()Z
public final fun component2 ()Ljava/lang/Integer;
public final fun component3 ()I
public final fun component4 ()Lkotlin/jvm/functions/Function3;
public final fun component5-3Sl7FsM ()Ljava/lang/String;
public final fun component6 ()Z
public final fun component8 ()Z
public final fun component5 ()Lkotlin/jvm/functions/Function2;
public final fun component6-3Sl7FsM ()Ljava/lang/String;
public final fun component7 ()Z
public final fun component9 ()Z
public final fun copy-rqXL5tM (Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Ljava/lang/String;ZZZZZ)Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;
public static synthetic fun copy-rqXL5tM$default (Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Ljava/lang/String;ZZZZZILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;
public final fun copy-bMNacXk (Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Ljava/lang/String;ZZZZZ)Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;
public static synthetic fun copy-bMNacXk$default (Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;Ljava/lang/Integer;Ljava/lang/Integer;ILkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Ljava/lang/String;ZZZZZILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/io/DisplayConfiguration;
public fun equals (Ljava/lang/Object;)Z
public final fun getCellContentLimit ()I
public final fun getCellFormatter ()Lkotlin/jvm/functions/Function3;
public final fun getDecimalFormat-3Sl7FsM ()Ljava/lang/String;
public final fun getDownsizeBufferedImage ()Z
public final fun getEnableFallbackStaticTables ()Z
public final fun getHeaderFormatter ()Lkotlin/jvm/functions/Function2;
public final fun getIsolatedOutputs ()Z
public final fun getNestedRowsLimit ()Ljava/lang/Integer;
public final fun getRowsLimit ()Ljava/lang/Integer;
Expand All @@ -6224,6 +6244,7 @@ public final class org/jetbrains/kotlinx/dataframe/io/DisplayConfiguration {
public final fun setDecimalFormat-h5o3lmc (Ljava/lang/String;)V
public final fun setDownsizeBufferedImage (Z)V
public final fun setEnableFallbackStaticTables (Z)V
public final fun setHeaderFormatter (Lkotlin/jvm/functions/Function2;)V
public final fun setIsolatedOutputs (Z)V
public final fun setNestedRowsLimit (Ljava/lang/Integer;)V
public final fun setRowsLimit (Ljava/lang/Integer;)V
Expand Down
22 changes: 18 additions & 4 deletions core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/format.kt
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ public fun <T, C> DataFrame<T>.format(vararg columns: KProperty<C>): FormatClaus
* If unspecified, all columns will be formatted.
*/
public fun <T, C> FormattedFrame<T>.format(columns: ColumnsSelector<T, C>): FormatClause<T, C> =
FormatClause(df, columns, formatter)
FormatClause(df, columns, formatter, oldHeaderFormatter = headerFormatter)

/**
* @include [CommonFormatDocs]
Expand Down Expand Up @@ -390,7 +390,13 @@ public fun <T> FormattedFrame<T>.format(): FormatClause<T, Any?> = FormatClause(
* Check out the full [Grammar][FormatDocs.Grammar].
*/
public fun <T, C> FormatClause<T, C>.where(filter: RowValueFilter<T, C>): FormatClause<T, C> =
FormatClause(filter = this.filter and filter, df = df, columns = columns, oldFormatter = oldFormatter)
FormatClause(
filter = this.filter and filter,
df = df,
columns = columns,
oldFormatter = oldFormatter,
oldHeaderFormatter = oldHeaderFormatter,
)

/**
* Only format the selected columns at given row indices.
Expand Down Expand Up @@ -780,7 +786,11 @@ public typealias CellFormatter<C> = FormattingDsl.(cell: C) -> CellAttributes?
*
* You can apply further formatting to this [FormattedFrame] by calling [format()][FormattedFrame.format] once again.
*/
public class FormattedFrame<T>(internal val df: DataFrame<T>, internal val formatter: RowColFormatter<T, *>? = null) {
public class FormattedFrame<T>(
internal val df: DataFrame<T>,
internal val formatter: RowColFormatter<T, *>? = null,
internal val headerFormatter: HeaderColFormatter<*>? = null,
) {

/**
* Returns a [DataFrameHtmlData] without additional definitions.
Expand Down Expand Up @@ -826,7 +836,10 @@ public class FormattedFrame<T>(internal val df: DataFrame<T>, internal val forma
/** Applies this formatter to the given [configuration] and returns a new instance. */
@Suppress("UNCHECKED_CAST")
public fun getDisplayConfiguration(configuration: DisplayConfiguration): DisplayConfiguration =
configuration.copy(cellFormatter = formatter as RowColFormatter<*, *>?)
configuration.copy(
cellFormatter = formatter as RowColFormatter<*, *>?,
headerFormatter = headerFormatter as HeaderColFormatter<*>?,
)
}

/**
Expand Down Expand Up @@ -858,6 +871,7 @@ public class FormatClause<T, C>(
internal val columns: ColumnsSelector<T, C> = { all().cast() },
internal val oldFormatter: RowColFormatter<T, C>? = null,
internal val filter: RowValueFilter<T, C> = { true },
internal val oldHeaderFormatter: HeaderColFormatter<*>? = null,
) {
override fun toString(): String =
"FormatClause(df=$df, columns=$columns, oldFormatter=$oldFormatter, filter=$filter)"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.jetbrains.kotlinx.dataframe.api

import org.jetbrains.kotlinx.dataframe.ColumnsSelector
import org.jetbrains.kotlinx.dataframe.DataFrame
import org.jetbrains.kotlinx.dataframe.annotations.AccessApiOverload
import org.jetbrains.kotlinx.dataframe.columns.ColumnReference
import org.jetbrains.kotlinx.dataframe.columns.ColumnWithPath
import org.jetbrains.kotlinx.dataframe.columns.UnresolvedColumnsPolicy
import org.jetbrains.kotlinx.dataframe.columns.toColumnSet
import org.jetbrains.kotlinx.dataframe.impl.getColumnPaths
import org.jetbrains.kotlinx.dataframe.util.DEPRECATED_ACCESS_API
import kotlin.reflect.KProperty

/**
* Formats the headers (column names) of the selected columns similarly to how [format] formats cell values.
*
* This does not immediately produce a [FormattedFrame]; instead it returns a [HeaderFormatClause] which must be
* finalized using [HeaderFormatClause.with].
*
* Header formatting is additive and supports nested column groups: styles specified for a parent [ColumnGroup]
* are inherited by its child columns unless overridden for the child.
*
* Examples:
* ```kt
* // center a single column header
* df.formatHeader { age }.with { attr("text-align", "center") }
*
* // style a whole group header and override one child
* df.formatHeader { name }.with { bold }
* .formatHeader { name.firstName }.with { textColor(green) }
* .toStandaloneHtml()
* ```
*/
public typealias HeaderColFormatter<C> = FormattingDsl.(col: ColumnWithPath<C>) -> CellAttributes?

/**
* Intermediate clause for header formatting, analogous to [FormatClause] but without rows.
*
* Use [with] to specify how to format the selected column headers, producing a [FormattedFrame].
*/
public class HeaderFormatClause<T, C>(
internal val df: DataFrame<T>,
internal val columns: ColumnsSelector<T, C> = { all().cast() },
internal val oldHeaderFormatter: HeaderColFormatter<C>? = null,
internal val oldCellFormatter: RowColFormatter<T, *>? = null,
) {
override fun toString(): String =
"HeaderFormatClause(df=$df, columns=$columns, oldHeaderFormatter=$oldHeaderFormatter, oldCellFormatter=$oldCellFormatter)"
}

// region DataFrame.formatHeader

/**
* Selects [columns] whose headers should be formatted; finalize with [HeaderFormatClause.with].
*/
public fun <T, C> DataFrame<T>.formatHeader(columns: ColumnsSelector<T, C>): HeaderFormatClause<T, C> =
HeaderFormatClause(this, columns)

/** Selects columns by [columns] names for header formatting. */
public fun <T> DataFrame<T>.formatHeader(vararg columns: String): HeaderFormatClause<T, Any?> =
formatHeader { columns.toColumnSet() }

/** Selects all columns for header formatting. */
public fun <T> DataFrame<T>.formatHeader(): HeaderFormatClause<T, Any?> = HeaderFormatClause(this)

@Deprecated(DEPRECATED_ACCESS_API)
@AccessApiOverload
public fun <T, C> DataFrame<T>.formatHeader(vararg columns: ColumnReference<C>): HeaderFormatClause<T, C> =
formatHeader { columns.toColumnSet() }

@Deprecated(DEPRECATED_ACCESS_API)
@AccessApiOverload
public fun <T, C> DataFrame<T>.formatHeader(vararg columns: KProperty<C>): HeaderFormatClause<T, C> =
formatHeader { columns.toColumnSet() }

// endregion

// region FormattedFrame.formatHeader

public fun <T, C> FormattedFrame<T>.formatHeader(columns: ColumnsSelector<T, C>): HeaderFormatClause<T, C> =
HeaderFormatClause(
df = df,
columns = columns,
oldHeaderFormatter = headerFormatter as HeaderColFormatter<C>?,
oldCellFormatter = formatter,
)

public fun <T> FormattedFrame<T>.formatHeader(vararg columns: String): HeaderFormatClause<T, Any?> =
formatHeader { columns.toColumnSet() }

public fun <T> FormattedFrame<T>.formatHeader(): HeaderFormatClause<T, Any?> =
HeaderFormatClause(
df = df,
oldHeaderFormatter = headerFormatter as HeaderColFormatter<Any?>?,
oldCellFormatter = formatter,
)

// endregion

// region terminal operations

@Suppress("UNCHECKED_CAST")
public fun <T, C> HeaderFormatClause<T, C>.with(formatter: HeaderColFormatter<C>): FormattedFrame<T> {
val paths = df.getColumnPaths(UnresolvedColumnsPolicy.Skip, columns).toSet()
val oldHeader = oldHeaderFormatter
val composedHeader: HeaderColFormatter<Any?> = { col ->
val parentCols = col.path.indices
.map { i -> col.path.take(i + 1) }
.dropLast(0) // include self and parents handled below
// Merge attributes from parents that are selected
val parentAttributes = parentCols
.dropLast(1)
.map { path -> ColumnWithPath(df[path], path) }
.map { parentCol ->
if (parentCol.path in
paths
) {
(oldHeader?.invoke(FormattingDsl, parentCol as ColumnWithPath<C>))
} else {
null
}
}
.reduceOrNull(CellAttributes?::and)
val selfAttr = if (col.path in paths) {
val oldAttr = oldHeader?.invoke(FormattingDsl, col as ColumnWithPath<C>)
oldAttr and formatter(FormattingDsl, col as ColumnWithPath<C>)
} else {
oldHeader?.invoke(FormattingDsl, col as ColumnWithPath<C>)
}
parentAttributes and selfAttr
}
@Suppress("UNCHECKED_CAST")
return FormattedFrame(df, oldCellFormatter, composedHeader)
}

// endregion
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,18 @@ internal inline fun <T, C> FormatClause<T, C>.formatImpl(
val clause = this
val columns = clause.df.getColumnPaths(UnresolvedColumnsPolicy.Skip, clause.columns).toSet()

return FormattedFrame(clause.df) { row, col ->
val oldAttributes = clause.oldFormatter?.invoke(FormattingDsl, row, col.cast())
if (col.path in columns) {
val value = col[row] as C
if (clause.filter(row, value)) {
return@FormattedFrame oldAttributes and formatter(FormattingDsl, row.cast(), col.cast())
return FormattedFrame(
df = clause.df,
formatter = { row, col ->
val oldAttributes = clause.oldFormatter?.invoke(FormattingDsl, row, col.cast())
if (col.path in columns) {
val value = col[row] as C
if (clause.filter(row, value)) {
return@FormattedFrame oldAttributes and formatter(FormattingDsl, row.cast(), col.cast())
}
}
}

oldAttributes
}
oldAttributes
},
headerFormatter = clause.oldHeaderFormatter,
)
}
Loading