What's the easiest way to load single band Landsat 8 rasters from AWS and combine them into a single multiband RDD? - landsat

I'm using geotrellis to load geotiff rasters from Landsat 8 that are sitting on S3. However, they are stored on a per-band basis. I can use S3GeoTiff class to load individual bands, e.g.:
val options = S3GeoTiffRDD.Options(getS3Client = () => S3Client.ANONYMOUS)
val rddBlue = S3GeoTiffRDD.spatial("landsat-pds", "L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B2.TIF", options)
val rddGreen = S3GeoTiffRDD.spatial("landsat-pds", "L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B3.TIF", options)
val rddRed = S3GeoTiffRDD.spatial("landsat-pds", "L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B4.TIF", options)
But how do I go about combining them to generate an RGB raster, e.g.
val rddRGB = ??? // something like combineRDDs(rddRed, rddGreen, rddBlue)

From the RDDs of single files with no maxTileSize option set, you'll end up with RDDs of full images (one element). I'd recommend setting the maxTileSize option.
There's an overload that allows you to place extra information into the key. This is how I'd approach this problem generically.
Here is some code that does what you are looking for, which utilizes those options:
import geotrellis.raster._
import geotrellis.spark._
import geotrellis.spark.io.s3._
import geotrellis.vector._
import org.apache.spark.SparkContext
import org.apache.spark.rdd._
import java.net.URI
import scala.math.BigDecimal.RoundingMode
implicit val sc: SparkContext =
geotrellis.spark.util.SparkUtils.createLocalSparkContext("local[*]", "landsat-example")
try {
val options =
S3GeoTiffRDD.Options(
getS3Client = () => S3Client.ANONYMOUS,
maxTileSize = Some(512),
numPartitions = Some(100)
)
type LandsatKey = (ProjectedExtent, URI, Int)
// For each RDD, we're going to include more information in the key, including:
// - the ProjectedExtent
// - the URI
// - the future band value
def uriToKey(bandIndex: Int): (URI, ProjectedExtent) => LandsatKey =
{ (uri, pe) =>
(pe, uri, bandIndex)
}
// Read an RDD of source tiles for each of the bands.
val redSourceTiles =
S3GeoTiffRDD[ProjectedExtent, LandsatKey, Tile](
"landsat-pds",
"L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B2.TIF",
uriToKey(0),
options
)
val greenSourceTiles =
S3GeoTiffRDD[ProjectedExtent, LandsatKey, Tile](
"landsat-pds",
"L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B3.TIF",
uriToKey(1),
options
)
val blueSourceTiles =
S3GeoTiffRDD[ProjectedExtent, LandsatKey, Tile](
"landsat-pds",
"L8/139/045/LC81390452014295LGN00/LC81390452014295LGN00_B4.TIF",
uriToKey(2),
options
)
// Union these together, rearrange the elements so that we'll be able to group by key,
// group them by key, and the rearrange again to produce multiband tiles.
val sourceTiles: RDD[(ProjectedExtent, MultibandTile)] = {
sc.union(redSourceTiles, greenSourceTiles, blueSourceTiles)
.map { case ((pe, uri, bandIndex), tile) =>
// Get the center of the tile, which we will join on
val (x, y) = (pe.extent.center.x, pe.extent.center.y)
// Round the center coordinates in case there's any floating point errors
val center =
(
BigDecimal(x).setScale(5, RoundingMode.HALF_UP).doubleValue(),
BigDecimal(y).setScale(5, RoundingMode.HALF_UP).doubleValue()
)
// Get the scene ID from the path
val sceneId = uri.getPath.split('/').reverse.drop(1).head
val newKey = (sceneId, center)
val newValue = (pe, bandIndex, tile)
(newKey, newValue)
}
.groupByKey()
.map { case (oldKey, groupedValues) =>
val projectedExtent = groupedValues.head._1
val bands = Array.ofDim[Tile](groupedValues.size)
for((_, bandIndex, tile) <- groupedValues) {
bands(bandIndex) = tile
}
(projectedExtent, MultibandTile(bands))
}
}
// From here, you could ingest the multiband layer.
// But for a simple test, we will rescale the bands and write them out to a single GeoTiff
import geotrellis.spark.tiling.FloatingLayoutScheme
import geotrellis.raster.io.geotiff.GeoTiff
val (_, metadata) = sourceTiles.collectMetadata[SpatialKey](FloatingLayoutScheme(512))
val tiles = sourceTiles.tileToLayout[SpatialKey](metadata)
val raster =
ContextRDD(tiles, metadata)
.withContext { rdd =>
rdd.mapValues { tile =>
// Magic numbers! These were created by fiddling around with
// numbers until some example landsat images looked good enough
// to put on a map for some other project.
val (min, max) = (4000, 15176)
def clamp(z: Int) = {
if(isData(z)) { if(z > max) { max } else if(z < min) { min } else { z } }
else { z }
}
val red = tile.band(0).map(clamp _).delayedConversion(ByteCellType).normalize(min, max, 0, 255)
val green = tile.band(1).map(clamp _).delayedConversion(ByteCellType).normalize(min, max, 0, 255)
val blue = tile.band(2).map(clamp _).delayedConversion(ByteCellType).normalize(min, max, 0, 255)
MultibandTile(red, green, blue)
}
}
.stitch
GeoTiff(raster, metadata.crs).write("/tmp/landsat-test.tif")
} finally {
sc.stop()
}

Related

How to set a determinate linear progress indicator

I have put a linear progress indicator in my code in Jetpack Compose but
don't know how to set a value. It's determinate so the user can see the
detailed progress but it's not working
First setting state
var ProgBarState by remember { mutableStateOf(0.1f) }
val onPGChange={pgState : Float -> ProgBarState = pgState}
val animatedProgress = animateFloatAsState(
targetValue = ProgBarState,
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
).value
afterwards ...
#Composable
fun CLProgressBar(ProgBarState : Float, onPGChange: (Float) -> Unit){
Column(
horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.background(Color(0xFF7DCEA0), )
)
) {
LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.height(20.dp),
backgroundColor = Color(0xFF7DCEA0),
color = Color(0xFF1C536F) ,
)
}
}
Don't know how to change the value of 'progress' any idea?
Setting ProgBarState=0.3f but nothing happend - progress bar stays indeterminate
When you use the LinearProgressIndicator without the progress parameter, it is indeterminate .
You can use something like:
//Indeterminate
LinearProgressIndicator()
//Determinate
LinearProgressIndicator(progress = value)
In your case just use:
LinearProgressIndicator(progress = animatedProgress)

Kotlin: Problem with List Filter by Multiple Conditions

I'm trying to match two lists to another. In one list are items of crypto trades, the other contains so called candlesticks, which represents a price of crypto asset for one minute. A candlestick is limited by open time and close time. One trade item belongs exactly to one candlestick set. So I step through the trades list an for each item I apply a filter of two conditions. Unfortunately the filter returns no matching data. When I compare the trades data with candlestick items manually, I get a match. Here is the code of the data filter.
TradesDbHandler(dbConnector).use { dbHandler ->
val rowsInTime = dbHandler.readTimeframe(startTime, buffer)
rowsInTime.distinctBy { it.symbol }.forEach {
val symbolFilter = rowsInTime.filter { row -> row.symbol == it.symbol }
val symbolMinTime = symbolFilter.minByOrNull { it.time }
val symbolMaxTime = symbolFilter.maxByOrNull { it.time }
val tempKlines = binanceClient.getCandleSticks( symbolMaxTime!!.symbol,
symbolMinTime!!.time,
symbolMaxTime!!.time ) {
log(">>> $it")
}
val klines = mutableListOf<KlineRow>()
klines.plusElement(tempKlines.filter { row ->
(row.opentime <= it.time) &&
(row.closetime >= it.time) })
}
}
The code was not the problem but the data. Therefore no matches could be found. Thread can be closed.

scalaFX - Titledpane: how do I get the heigth of the content?

I created a TiteldPane in scalafx
val titled: TitledPane = new TitledPane()
and put some nodes in it for my GUI.
Later I want to read out the heigth of the content of titled.
In javaFX this would be done with:
((Region) titled.getContent()).getHeight()
But if I try to read the height of the content in scala with:
titled.content.height
the height is marked as deprecated and does not compile. I've got a hint to github (scalafx/issue69) that explains why it is deprecated but does not explain how it can be done instead.
Just to clarify: I want to read out the height of the content of the titledpane, not just titled.heigth.
When titled is closed, then titled.height is 0, but I want to know what it would be when it is expanded (to detect when it has finished expanding actually).
So, how can I do this in scalafx?
EDIT:
Here is a example that shows the described error
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.beans.property.DoubleProperty
import scalafx.beans.value.ObservableValue
import scalafx.collections.ObservableBuffer
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.cell.TextFieldListCell
import scalafx.scene.control.{Button, ListView, TitledPane}
import scalafx.scene.layout.BorderPane
object TitledPaneEndOfExpansion extends JFXApp {
val expandedHeight = new DoubleProperty()
val data: ObservableBuffer[String] = new ObservableBuffer[String]() ++= List("some", "content", "for", "testing")
stage = new JFXApp.PrimaryStage {
title = "JavaFX: edit after rendering test"
val list: ListView[String] = new ListView[String](data) {
editable = true
cellFactory = TextFieldListCell.forListView()
height.onChange { (source: ObservableValue[Double, Number], oldValue: Number, newValue: Number) =>
expandedHeight.value = titled.content.height
println("old height is: " + oldValue.doubleValue() + " new height is: " + newValue.doubleValue())
if (newValue.doubleValue() == expandedHeight.value) {
edit(1)
}
}
}
val titled: TitledPane = new TitledPane {
text = "titled"
content = list
}
scene = new Scene {
root = new BorderPane {
center = titled
bottom = new Button() {
text = "edit cell 1"
onAction = { _: ActionEvent => list.edit(1) }
}
}
}
expandedHeight.value = titled.content.height //set to 400
list.edit(1)
}
}
And here is the buid.sbt file:
name := "JavaFXrenderingProblem"
version := "0.1"
scalaVersion := "2.13.3"
libraryDependencies += "org.scalafx" %% "scalafx" % "15.0.1-R21"
libraryDependencies += "org.controlsfx" % "controlsfx" % "8.40.18"
// Prevent startup bug in JavaFX
fork := true
// Tell Javac and scalac to build for jvm 1.8
javacOptions ++= Seq("-source", "1.8", "-target", "1.8")
scalacOptions += "-target:jvm-1.8"
scalacOptions += "-feature"
When I just compile with plain sbt i get the compile error-message:
[info] compiling 1 Scala source to ... JavaFXrenderingProblem\target\scala-2.13\classes ...
[error] ... JavaFXrenderingProblem\src\main\scala\TitledPaneEndOfExpansion.scala:38:47: value height is not a member of scalafx.beans.property.ObjectProperty[javafx.scene.Node]
[error] expandedHeight.value = titled.content.height
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 3 s, completed 03.05.2021 11:09:02
I actually get two errors when I execute sbt run on your code, and I do not get a deprecation error:
[info] compiling 1 Scala source to C:\Users\SomeUser\src\SFC\target\scala-2.13\classes ...
[error] C:\Users\SomeUser\src\SFX\src\main\scala\TitledPaneEndOfExpansion.scala:23:41: value height is not a member of scalafx.beans.property.ObjectProperty[javafx.scene.Node]
[error] expandedHeight.value = titled.content.height
[error] ^
[error] C:\Users\MichaelAllen\src\SOSFX\src\main\scala\TitledPaneEndOfExpansion.scala:45:40: value height is not a member of scalafx.beans.property.ObjectProperty[javafx.scene.Node]
[error] expandedHeight.value = titled.content.height //set to 400
[error] ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 3 s, completed May 3, 2021 9:58:00 AM
From your code, the list value returns the contents of the TitledPane instance, titled, as a ListView[String]. It is this object whose height method you're trying to call. Correct?
The primary problem is that the content method of titled doesn't know enough about the type of the object that titled is storing. All it knows is that it is derived from javafx.scene.Node. Such Node instances do not have a height property, and hence your errors. (It's actually a little more complicated than that, but that's the simplest way to explain the issue.)
However, you already have a reference to the object that is the content of titled: list. So you can replace the second reference to titled.content.height with list.height. The first reference, in list's height's onChanged method, is accessible through the source parameter (it identifies the property that changed value, namely list.height in this case). So you can replace title.content.height with source in this case.
I notice that you're using a DoubleProperty type for expandedHeight in your example, but you need to keep looking at the value of the associated types. That's not very idiomatic. If you don't need this value to be reactive, a simple Double would suffice (but this would require that expandedHeight be declared as a var).
Combined, this produces the following code:
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.beans.property.DoubleProperty
import scalafx.beans.value.ObservableValue
import scalafx.collections.ObservableBuffer
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.cell.TextFieldListCell
import scalafx.scene.control.{Button, ListView, TitledPane}
import scalafx.scene.layout.BorderPane
object TitledPaneEndOfExpansion extends JFXApp {
var expandedHeight: Double = _
val data: ObservableBuffer[String] = new ObservableBuffer[String]() ++= List("some", "content", "for", "testing")
stage = new JFXApp.PrimaryStage {
title = "JavaFX: edit after rendering test"
val list: ListView[String] = new ListView[String](data) {
editable = true
cellFactory = TextFieldListCell.forListView()
height.onChange { (source: ObservableValue[Double, Number], oldValue: Number, newValue: Number) =>
expandedHeight = source.value
println("old height is: " + oldValue.doubleValue() + " new height is: " + newValue.doubleValue())
if (newValue.doubleValue() == expandedHeight) {
edit(1)
}
}
}
val titled: TitledPane = new TitledPane {
text = "titled"
content = list
}
scene = new Scene {
root = new BorderPane {
center = titled
bottom = new Button() {
text = "edit cell 1"
onAction = { _: ActionEvent => list.edit(1) }
}
}
}
expandedHeight = list.height.value //set to 400
list.edit(1)
}
}
Your code then compiles and runs.
Updated
ScalaFX is simply a wrapper for JavaFX: each JavaFX type has a corresponding ScalaFX type. ScalaFX provides implicit conversion functions to seamlessly convert, say, a JavaFX TitledPane to a ScalaFX TitledPane, and vice versa. However, there's no inheritance relationship between the two sets of objects. That is, a JavaFX TitledPane has no type relationship to a ScalaFX TitledPane. Casting between the two sets of objects is therefore a complicated process.
If you wanted to be able to cast titled.content correctly in order to access the height property of the contents more directly, you would need to get the property's value and explicitly pattern match on the result with the JavaFX version of the object, as follows:
import javafx.scene.control.{ListView => JFXListView}
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.beans.property.DoubleProperty
import scalafx.beans.value.ObservableValue
import scalafx.collections.ObservableBuffer
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.cell.TextFieldListCell
import scalafx.scene.control.{Button, ListView, TitledPane}
import scalafx.scene.layout.BorderPane
object TitledPaneEndOfExpansion extends JFXApp {
var expandedHeight: Double = _
val data: ObservableBuffer[String] = new ObservableBuffer[String]() ++= List("some", "content", "for", "testing")
stage = new JFXApp.PrimaryStage {
title = "JavaFX: edit after rendering test"
val list: ListView[String] = new ListView[String](data) {
editable = true
cellFactory = TextFieldListCell.forListView()
height.onChange { (source: ObservableValue[Double, Number], oldValue: Number, newValue: Number) =>
expandedHeight = titled.content.value match {
case lv: JFXListView[_] => lv.height.value
case _ => {
throw new RuntimeException(s"Unexpected content type: ${titled.content.getClass.getCanonicalName}")
}
}
println("old height is: " + oldValue.doubleValue() + " new height is: " + newValue.doubleValue())
if (newValue.doubleValue() == expandedHeight) {
edit(1)
}
}
}
val titled: TitledPane = new TitledPane {
text = "titled"
content = list
}
scene = new Scene {
root = new BorderPane {
center = titled
bottom = new Button() {
text = "edit cell 1"
onAction = { _: ActionEvent => list.edit(1) }
}
}
}
expandedHeight = titled.content.value match { //set to 400
case lv: JFXListView[_] => lv.height.value
case _ => throw new RuntimeException(s"Unexpected content type: ${titled.content.getClass.getCanonicalName}")
}
list.edit(1)
}
}
If you didn't have any other means of referencing the list object, that would be your only option.

Scala Futures Returning Empty List after Await

I have a program that performs an:
Await.result(Processor.validateEntries(queuedEntries)), Duration.Inf)
And the validateEntries method calls some other method that performs:
val validatedEntries: ListBuffer[Entries] = new ListBuffer[Entries]
for (entry <- queuedEntries) {
checkEntry(entry.name).map(.......... validatedEntries += Entries(...) )
}
Future(validatedEntries.toList)
where checkEntry returns a Future[Boolean].
def checkEntry(name: String): Future[Boolean] = {
checkNameAlreadyExists(name).flatMap(exists =>
buildRequest(exists, name).map(response => {
if (!response.contains("error")) {
true
} else {
false
}
})
)
}
At the top level where I perform the Await.result I also get back an empty list: List(). Any suggestions would greatly help!
Mixing mutable collections and concurrency is not a good idea. Consider refactoring checkEntry to return, say, Future[Option[Entry]] instead of Future[Boolean], where Some would represent successful validation, whilst None unssucessful, and then you might do something like
case class Entry(v: Int)
val queuedEntries = List(Entry(1), Entry(2), Entry(3))
def checkEntry(entry: Entry): Future[Option[Entry]] = ???
Future
.traverse(queuedEntries)(checkEntry)
.map(_.flatten)
If keeping checkEntry as it is, then you might try something like
case class Entry(v: Int)
val queuedEntries = List(Entry(1), Entry(2), Entry(3))
def checkEntry(entry: Entry): Future[Boolean] = Future(Random.nextBoolean)
Future
.traverse(queuedEntries)(checkEntry)
.map(checkedEntries => checkedEntries zip queuedEntries)
.map(_.collect { case (validated, entry) if validated => entry} )
You have to use for comprehension. Basically first you have to read the list and in yield, you have to call function one by one and wait for future to complete by yield
package com.vimit.StackOverflow
import scala.concurrent._
import ExecutionContext.Implicits.global
object FutureProblem extends App {
val list = List(1, 2, 3)
val outputList = List()
val result = for {
value <- list
} yield {
for {
result <- getValue(value).map(res => outputList ++ List(value))
} yield result
}
print(result)
def getValue(value: Int) = Future(value)
}

Performance Issue when retrieving transaction details from Quorum Blockchain

I have experienced performance issue when retrieving transaction details such as transaction originator and transaction recipient
from the Quorum blockchain.
The Javascript For loop and Web3.eth.contract(abi).at(address2).totalTransactions is used to retrieve transaction details and
then append to HTML table.
My performance problem is that the retrieval of few lines of transaction data from Quorum blockchain takes about 30 seconds.
Moreover, I am using web3-quorum#0.1.1 and quorum-js#0.3.0.
$('#get-tran').click(() => {
// Get Tran History
var tranId = 0;
let w2Contract=web3w2.eth.contract(abi).at(address2);
let tottr = w2Contract.totalTransactions();
//Clear the old table content first
$("#t02 tr").remove();
var i=0;
for (i = 0; i <= w2Contract.totalTransactions()-1; i++) {
tranId = i;
let tranHash = w2Contract.transactionIDs(i);
let trDetails1 = w2Contract.transactions(tranHash);
console.log(`Tran details ${trDetails1}`);
console.log(`Tran Detail 1: ${trDetails1[1]}`);
console.log(`Tran Detail 2: ${trDetails1[2]}`);
console.log(`Tran Detail 0: ${trDetails1[0]}`);
var tableRef = document.getElementById('t02').getElementsByTagName('tbody')[0];
// Insert a row at the end of the table
let newRow = tableRef.insertRow(-1);
// Insert a cell in the row at index 0
let newCell = newRow.insertCell(0);
// Append a text node to the cell
let newText = document.createTextNode(`${tranId}`);
newCell.appendChild(newText);
// Insert a cell in the row at index 1
let newCell1 = newRow.insertCell(1);
// Append a text node to the cell
let newText1 = document.createTextNode(`${trDetails1[1]}`);
console.log(`newText1 at index 1 ${newText1}`);
// w2 > w1
if ((trDetails1[1] == '0xf9a2cb34b6b5fd7a2ac0c2e9b2b9406d6daffbd4') &&
(trDetails1[2] == '0x180893a0ec847fa8c92786791348d7d65916acbb')) {
newText1.textContent = 'Stock In'
} else if
(trDetails1[1] == '0x180893a0ec847fa8c92786791348d7d65916acbb') {
newText1.textContent = 'Pier Company'
} else if (trDetails1[1] == '0xf9a2cb34b6b5fd7a2ac0c2e9b2b9406d6daffbd4') {
newText1.textContent = 'Warehouse Company'
}
newCell1.appendChild(newText1);
// Insert a cell in the row at index 2
let newCell2 = newRow.insertCell(2);
// Append a text node to the cell
let newText2 = document.createTextNode(`${trDetails1[2]}`);
console.log(`newText1 at index 2 ${newText1}`);
if (trDetails1[2] == '0xf9a2cb34b6b5fd7a2ac0c2e9b2b9406d6daffbd4') {
newText2.textContent = 'Warehouse Company'
}
if (trDetails1[2] == '0x180893a0ec847fa8c92786791348d7d65916acbb') {
newText2.textContent = 'Pier Company'
}
if (trDetails1[2] == '0xc8f717ba9593dc9d45c4518cf444d2cbd08af24d') {
newText2.textContent = 'Removal'
}
newCell2.appendChild(newText2);
// Insert a cell in the row at index 3
let newCell3 = newRow.insertCell(3);
// Append a text node to the cell
let newText3 = document.createTextNode(`${trDetails1[0]}`);
console.log(`newText3 at index 3 ${newText3}`);
newCell3.appendChild(newText3);
// Insert a cell in the row at index 4
let newCell4 = newRow.insertCell(4);
// Append a text node to the cell
let newText4 = document.createTextNode(`${trDetails1[3]}`);
console.log(`newText1 at index 4 ${newText4}`);
if (trDetails1[3] ) {
newText4.textContent = 'Confirmed'
} else {
newText4.textContent = 'Pending'
}
newCell4.appendChild(newText4);
}
});