Skip to content

Commit 1ea29f2

Browse files
authored
Merge pull request #305 from s22s/fix/304
Fixes 304; improves ShowableTile.
2 parents 1fff31b + 74d58bf commit 1ea29f2

File tree

8 files changed

+72
-57
lines changed

8 files changed

+72
-57
lines changed

core/src/main/scala/org/locationtech/rasterframes/expressions/transformers/SetCellType.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ case class SetCellType(tile: Expression, cellType: Expression)
5757
extends BinaryExpression with CodegenFallback {
5858
def left = tile
5959
def right = cellType
60-
override def nodeName: String = "set_cell_type"
60+
override def nodeName: String = "rf_convert_cell_type"
6161
override def dataType: DataType = left.dataType
6262

6363
override def checkInputDataTypes(): TypeCheckResult = {

core/src/main/scala/org/locationtech/rasterframes/expressions/transformers/SetNoDataValue.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
package org.locationtech.rasterframes.expressions.transformers
2323

2424
import com.typesafe.scalalogging.LazyLogging
25-
import geotrellis.raster.Tile
2625
import org.apache.spark.sql.Column
2726
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult
2827
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.{TypeCheckFailure, TypeCheckSuccess}
@@ -33,7 +32,7 @@ import org.apache.spark.sql.rf.TileUDT
3332
import org.apache.spark.sql.types._
3433
import org.locationtech.rasterframes.encoders.CatalystSerializer._
3534
import org.locationtech.rasterframes.expressions.DynamicExtractors._
36-
import org.locationtech.rasterframes.expressions.{fpTile, row}
35+
import org.locationtech.rasterframes.expressions.row
3736

3837
@ExpressionDescription(
3938
usage = "_FUNC_(tile, value) - Set the NoData value for the given tile.",
@@ -64,20 +63,19 @@ case class SetNoDataValue(left: Expression, right: Expression) extends BinaryExp
6463
override protected def nullSafeEval(input1: Any, input2: Any): Any = {
6564
implicit val tileSer = TileUDT.tileSerializer
6665
val (leftTile, leftCtx) = tileExtractor(left.dataType)(row(input1))
66+
6767
val result = numberArgExtractor(right.dataType)(input2) match {
68-
case DoubleArg(d) => op(fpTile(leftTile), d)
69-
case IntegerArg(i) => op(leftTile, i)
68+
case DoubleArg(d) => leftTile.withNoData(Some(d))
69+
case IntegerArg(i) => leftTile.withNoData(Some(i.toDouble))
7070
}
7171

7272
leftCtx match {
7373
case Some(ctx) => ctx.toProjectRasterTile(result).toInternalRow
7474
case None => result.toInternalRow
7575
}
7676
}
77-
78-
protected def op(left: Tile, right: Double): Tile = left.withNoData(Some(right))
79-
protected def op(left: Tile, right: Int): Tile = left.withNoData(Some(right))
8077
}
78+
8179
object SetNoDataValue {
8280
def apply(left: Column, right: Column): Column =
8381
new Column(SetNoDataValue(left.expr, right.expr))

core/src/main/scala/org/locationtech/rasterframes/functions/package.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ package object functions {
9090
}
9191
}
9292

93-
94-
9593
/** Alias for constant tiles of zero */
9694
private[rasterframes] val tileZeros: (Int, Int, String) Tile = (cols, rows, cellTypeName)
9795
makeConstantTile(0, cols, rows, cellTypeName)

core/src/main/scala/org/locationtech/rasterframes/tiles/ShowableTile.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
package org.locationtech.rasterframes.tiles
2323
import org.locationtech.rasterframes._
24-
import geotrellis.raster.Tile
24+
import geotrellis.raster.{Tile, isNoData}
2525

2626
class ShowableTile(val delegate: Tile) extends FixedDelegatingTile {
2727
override def equals(obj: Any): Boolean = obj match {
@@ -39,8 +39,14 @@ object ShowableTile {
3939
val dims = tile.dimensions
4040

4141
val data = if (tile.cellType.isFloatingPoint)
42-
tile.toArrayDouble()
43-
else tile.toArray()
42+
tile.toArrayDouble().map {
43+
case c if isNoData(c) => "--"
44+
case c => c.toString
45+
}
46+
else tile.toArray().map {
47+
case c if isNoData(c) => "--"
48+
case c => c.toString
49+
}
4450

4551
val cells = if(tile.size <= maxCells) {
4652
data.mkString("[", ",", "]")

core/src/test/scala/org/locationtech/rasterframes/ExplodeSpec.scala

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -110,45 +110,6 @@ class ExplodeSpec extends TestEnvironment with TestData {
110110
cells.count(_.isNaN) should be(tiles.size)
111111
}
112112

113-
it("should convert tile into array") {
114-
val query = sql(
115-
"""select rf_tile_to_array_int(
116-
| rf_make_constant_tile(1, 10, 10, 'int8raw')
117-
|) as intArray
118-
|""".stripMargin)
119-
query.as[Array[Int]].first.sum should be (100)
120-
121-
val tile = FloatConstantTile(1.1f, 10, 10, FloatCellType)
122-
val df = Seq[Tile](tile).toDF("tile")
123-
val arrayDF = df.select(rf_tile_to_array_double($"tile").as[Array[Double]])
124-
arrayDF.first().sum should be (110.0 +- 0.0001)
125-
126-
checkDocs("rf_tile_to_array_int")
127-
}
128-
129-
it("should convert an array into a tile") {
130-
val tile = TestData.randomTile(10, 10, FloatCellType)
131-
val df = Seq[Tile](tile, null).toDF("tile")
132-
val arrayDF = df.withColumn("tileArray", rf_tile_to_array_double($"tile"))
133-
134-
val back = arrayDF.withColumn("backToTile", rf_array_to_tile($"tileArray", 10, 10))
135-
136-
val result = back.select($"backToTile".as[Tile]).first
137-
138-
assert(result.toArrayDouble() === tile.toArrayDouble())
139-
140-
// Same round trip, but with SQL expression for rf_array_to_tile
141-
val resultSql = arrayDF.selectExpr("rf_array_to_tile(tileArray, 10, 10) as backToTile").as[Tile].first
142-
143-
assert(resultSql.toArrayDouble() === tile.toArrayDouble())
144-
145-
val hasNoData = back.withColumn("withNoData", rf_with_no_data($"backToTile", 0))
146-
147-
val result2 = hasNoData.select($"withNoData".as[Tile]).first
148-
149-
assert(result2.cellType.asInstanceOf[UserDefinedNoData[_]].noDataValue === 0)
150-
}
151-
152113
it("should reassemble single exploded tile") {
153114
val tile = TestData.randomTile(10, 10, FloatCellType)
154115
val df = Seq[Tile](tile).toDF("tile")

core/src/test/scala/org/locationtech/rasterframes/RasterFunctionsSpec.scala

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,20 @@ class RasterFunctionsSpec extends TestEnvironment with RasterMatchers {
120120
it("should change NoData value") {
121121
val df = Seq((TestData.injectND(7)(three), TestData.injectND(12)(two))).toDF("three", "two")
122122

123-
val ct = df.select(
123+
val ndCT = df.select(
124124
rf_with_no_data($"three", 3) as "three",
125-
rf_with_no_data($"two", 2) as "two"
125+
rf_with_no_data($"two", 2.0) as "two"
126126
)
127127

128-
val (cnt3, cnt2) = ct.select(rf_no_data_cells($"three"), rf_no_data_cells($"two")).as[(Long, Long)].first()
128+
val (cnt3, cnt2) = ndCT.select(rf_no_data_cells($"three"), rf_no_data_cells($"two")).as[(Long, Long)].first()
129129

130130
cnt3 should be ((cols * rows) - 7)
131131
cnt2 should be ((cols * rows) - 12)
132132

133133
checkDocs("rf_with_no_data")
134+
135+
// Should maintain original cell type.
136+
ndCT.select(rf_cell_type($"two")).first().withDefaultNoData() should be(ct.withDefaultNoData())
134137
}
135138
}
136139

@@ -568,6 +571,48 @@ class RasterFunctionsSpec extends TestEnvironment with RasterMatchers {
568571
}
569572
}
570573

574+
describe("array operations") {
575+
it("should convert tile into array") {
576+
val query = sql(
577+
"""select rf_tile_to_array_int(
578+
| rf_make_constant_tile(1, 10, 10, 'int8raw')
579+
|) as intArray
580+
|""".stripMargin)
581+
query.as[Array[Int]].first.sum should be (100)
582+
583+
val tile = FloatConstantTile(1.1f, 10, 10, FloatCellType)
584+
val df = Seq[Tile](tile).toDF("tile")
585+
val arrayDF = df.select(rf_tile_to_array_double($"tile").as[Array[Double]])
586+
arrayDF.first().sum should be (110.0 +- 0.0001)
587+
588+
checkDocs("rf_tile_to_array_int")
589+
checkDocs("rf_tile_to_array_double")
590+
}
591+
592+
it("should convert an array into a tile") {
593+
val tile = TestData.randomTile(10, 10, FloatCellType)
594+
val df = Seq[Tile](tile, null).toDF("tile")
595+
val arrayDF = df.withColumn("tileArray", rf_tile_to_array_double($"tile"))
596+
597+
val back = arrayDF.withColumn("backToTile", rf_array_to_tile($"tileArray", 10, 10))
598+
599+
val result = back.select($"backToTile".as[Tile]).first
600+
601+
assert(result.toArrayDouble() === tile.toArrayDouble())
602+
603+
// Same round trip, but with SQL expression for rf_array_to_tile
604+
val resultSql = arrayDF.selectExpr("rf_array_to_tile(tileArray, 10, 10) as backToTile").as[Tile].first
605+
606+
assert(resultSql.toArrayDouble() === tile.toArrayDouble())
607+
608+
val hasNoData = back.withColumn("withNoData", rf_with_no_data($"backToTile", 0))
609+
610+
val result2 = hasNoData.select($"withNoData".as[Tile]).first
611+
612+
assert(result2.cellType.asInstanceOf[UserDefinedNoData[_]].noDataValue === 0)
613+
}
614+
}
615+
571616
describe("analytical transformations") {
572617
it("should compute rf_normalized_difference") {
573618
val df = Seq((three, two)).toDF("three", "two")

core/src/test/scala/org/locationtech/rasterframes/TileUDTSpec.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
*/
2121

2222
package org.locationtech.rasterframes
23-
import geotrellis.raster.{CellType, Tile}
23+
import geotrellis.raster
24+
import geotrellis.raster.{CellType, NoNoData, Tile}
2425
import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder
2526
import org.apache.spark.sql.rf._
2627
import org.apache.spark.sql.types.StringType
@@ -98,6 +99,12 @@ class TileUDTSpec extends TestEnvironment with TestData with Inspectors {
9899
forEveryConfig { tile =>
99100
val stringified = Seq(tile).toDF("tile").select($"tile".cast(StringType)).as[String].first()
100101
stringified should be(ShowableTile.show(tile))
102+
103+
if(!tile.cellType.isInstanceOf[NoNoData]) {
104+
val withNd = tile.mutable
105+
withNd.update(0, raster.NODATA)
106+
ShowableTile.show(withNd) should include("--")
107+
}
101108
}
102109
}
103110
}

pyrasterframes/src/main/python/pyrasterframes/rf_ipython.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def _safe_tile_to_html(t):
153153
return return_html
154154

155155

156-
def spark_df_to_markdown(df, num_rows=5, truncate=True, vertical=False):
156+
def spark_df_to_markdown(df, num_rows=5, truncate=False, vertical=False):
157157
from pyrasterframes import RFContext
158158
return RFContext.active().call("_dfToMarkdown", df._jdf, num_rows, truncate)
159159

0 commit comments

Comments
 (0)