Skip to content

Commit

Permalink
Automated commit of generated code
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Nov 12, 2024
1 parent 125def0 commit 3f054ab
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.jetbrains.kotlinx.dataframe.AnyCol
import org.jetbrains.kotlinx.dataframe.AnyFrame
import org.jetbrains.kotlinx.dataframe.AnyRow
import org.jetbrains.kotlinx.dataframe.DataFrame
import org.jetbrains.kotlinx.dataframe.api.FormattedFrame
import org.jetbrains.kotlinx.dataframe.api.FormattingDSL
import org.jetbrains.kotlinx.dataframe.api.RowColFormatter
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
Expand Down Expand Up @@ -138,13 +139,13 @@ internal var sessionId = (Random().nextInt() % 128) shl 24
internal fun nextTableId() = sessionId + (tableInSessionId++)

internal fun AnyFrame.toHtmlData(
configuration: DisplayConfiguration = DisplayConfiguration.DEFAULT,
defaultConfiguration: DisplayConfiguration = DisplayConfiguration.DEFAULT,
cellRenderer: CellRenderer,
): DataFrameHtmlData {
val scripts = mutableListOf<String>()
val queue = LinkedList<Pair<AnyFrame, Int>>()
val queue = LinkedList<RenderingQueueItem>()

fun AnyFrame.columnToJs(col: AnyCol, rowsLimit: Int?): ColumnDataForJs {
fun AnyFrame.columnToJs(col: AnyCol, rowsLimit: Int?, configuration: DisplayConfiguration): ColumnDataForJs {
val values = if (rowsLimit != null) rows().take(rowsLimit) else rows()
val scale = if (col.isNumber()) col.asNumbers().scale() else 1
val format = if (scale > 0) {
Expand All @@ -155,13 +156,15 @@ internal fun AnyFrame.toHtmlData(
val renderConfig = configuration.copy(decimalFormat = format)
val contents = values.map {
val value = it[col]
if (value is AnyFrame) {
if (value.isEmpty()) {
val content = value.toDataFrameLikeOrNull()
if (content != null) {
val df = content.df()
if (df.isEmpty()) {
HtmlContent("", null)
} else {
val id = nextTableId()
queue.add(value to id)
DataFrameReference(id, value.size)
queue.add(RenderingQueueItem(df, id, content.configuration(defaultConfiguration)))
DataFrameReference(id, df.size)
}
} else {
val html =
Expand All @@ -174,20 +177,25 @@ internal fun AnyFrame.toHtmlData(
HtmlContent(html, style)
}
}
val nested = if (col is ColumnGroup<*>) {
col.columns().map { col.columnToJs(it, rowsLimit, configuration) }
} else {
emptyList()
}
return ColumnDataForJs(
column = col,
nested = if (col is ColumnGroup<*>) col.columns().map { col.columnToJs(it, rowsLimit) } else emptyList(),
nested = nested,
rightAlign = col.isSubtypeOf<Number?>(),
values = contents,
)
}

val rootId = nextTableId()
queue.add(this to rootId)
queue.add(RenderingQueueItem(this, rootId, defaultConfiguration))
while (!queue.isEmpty()) {
val (nextDf, nextId) = queue.pop()
val (nextDf, nextId, configuration) = queue.pop()
val rowsLimit = if (nextId == rootId) configuration.rowsLimit else configuration.nestedRowsLimit
val preparedColumns = nextDf.columns().map { nextDf.columnToJs(it, rowsLimit) }
val preparedColumns = nextDf.columns().map { nextDf.columnToJs(it, rowsLimit, configuration) }
val js = tableJs(preparedColumns, nextId, rootId, nextDf.nrow)
scripts.add(js)
}
Expand All @@ -196,6 +204,36 @@ internal fun AnyFrame.toHtmlData(
return DataFrameHtmlData(style = "", body = body, script = script)
}

private interface DataFrameLike {
fun configuration(default: DisplayConfiguration): DisplayConfiguration

fun df(): AnyFrame
}

private fun Any?.toDataFrameLikeOrNull(): DataFrameLike? =
when (this) {
is AnyFrame -> {
object : DataFrameLike {
override fun configuration(default: DisplayConfiguration) = default

override fun df(): AnyFrame = this@toDataFrameLikeOrNull
}
}

is FormattedFrame<*> -> {
object : DataFrameLike {
override fun configuration(default: DisplayConfiguration): DisplayConfiguration =
getDisplayConfiguration(default)

override fun df(): AnyFrame = df
}
}

else -> null
}

private data class RenderingQueueItem(val df: DataFrame<*>, val id: Int, val configuration: DisplayConfiguration)

private const val DEFAULT_HTML_IMG_SIZE = 100

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ public fun DataFrame.Companion.readJsonStr(
* @param header Optional list of column names. If given, [text] will be read like an object with [header] being the keys.
* @return [DataRow] from the given [text].
*/
@Refine
@Interpretable("DataRowReadJsonStr")
public fun DataRow.Companion.readJsonStr(
@Language("json") text: String,
header: List<String> = emptyList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ package org.jetbrains.kotlinx.dataframe.rendering

import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.string.shouldInclude
import io.kotest.matchers.string.shouldNotContain
import org.jetbrains.kotlinx.dataframe.DataColumn
import org.jetbrains.kotlinx.dataframe.api.CellAttributes
import org.jetbrains.kotlinx.dataframe.api.add
import org.jetbrains.kotlinx.dataframe.api.asColumnGroup
import org.jetbrains.kotlinx.dataframe.api.columnOf
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
import org.jetbrains.kotlinx.dataframe.api.emptyDataFrame
import org.jetbrains.kotlinx.dataframe.api.format
import org.jetbrains.kotlinx.dataframe.api.group
import org.jetbrains.kotlinx.dataframe.api.into
import org.jetbrains.kotlinx.dataframe.api.move
import org.jetbrains.kotlinx.dataframe.api.named
import org.jetbrains.kotlinx.dataframe.api.parse
import org.jetbrains.kotlinx.dataframe.api.schema
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
import org.jetbrains.kotlinx.dataframe.api.with
import org.jetbrains.kotlinx.dataframe.io.DisplayConfiguration
import org.jetbrains.kotlinx.dataframe.io.escapeHTML
import org.jetbrains.kotlinx.dataframe.io.formatter
Expand All @@ -24,7 +28,9 @@ import org.jetbrains.kotlinx.dataframe.io.maxWidth
import org.jetbrains.kotlinx.dataframe.io.print
import org.jetbrains.kotlinx.dataframe.io.renderToString
import org.jetbrains.kotlinx.dataframe.io.renderToStringTable
import org.jetbrains.kotlinx.dataframe.io.tableInSessionId
import org.jetbrains.kotlinx.dataframe.io.toHTML
import org.jetbrains.kotlinx.dataframe.io.toStandaloneHTML
import org.jetbrains.kotlinx.dataframe.jupyter.DefaultCellRenderer
import org.jetbrains.kotlinx.dataframe.jupyter.RenderedContent
import org.jetbrains.kotlinx.dataframe.samples.api.TestBase
Expand Down Expand Up @@ -196,4 +202,29 @@ class RenderingTests : TestBase() {
val rendered = schema.toString()
rendered shouldBe "a: Int?\nb: IntArray\nc: Array<Int>\nd: Array<Int?>"
}

@Test
fun `render nested FormattedFrame as DataFrame`() {
val empty = object : CellAttributes {
override fun attributes(): List<Pair<String, String>> = emptyList()
}
val df = dataFrameOf("b")(1)

val formatted = dataFrameOf("a")(df.format { all() }.with { empty })
val nestedFrame = dataFrameOf("a")(df)
val configuration = DisplayConfiguration(enableFallbackStaticTables = false)
tableInSessionId = 0
val formattedHtml = formatted.toStandaloneHTML(configuration).toString()
tableInSessionId = 0
val regularHtml = nestedFrame.toStandaloneHTML(configuration).toString()

formattedHtml.replace("api.FormattedFrame", "DataFrame") shouldBe regularHtml
}

@Test
fun `render cell attributes for nested FormattedFrame`() {
val df = dataFrameOf("a")(dataFrameOf("b")(1).format { all() }.with { background(green) })
val html = df.toStandaloneHTML()
html.toString() shouldInclude "style: \"background-color"
}
}

0 comments on commit 3f054ab

Please sign in to comment.