How to generate custom tooltips in XPlot.GoogleCharts Treemap (F#)? - f#

I want to generate a tooltip as described on the Google site (https://developers.google.com/chart/interactive/docs/gallery/treemap#tooltips),
and i cannot figure out how.
I took the example from https://fslab.org/XPlot/chart/google-treemap-chart.html and want to modify it, so that i have custom tooltips:
let tt =
Tooltip (
//...
)
let options =
Options(
title = "Treemap",
minColor= "#009688",
midColor= "#f7f7f7",
maxColor= "#ee8100",
headerHeight = 50,
headerColor = "#9ebcda",
fontColor = "black",
tooltip = tt,
showTooltips = true,
showScale = true
)
data
|> Chart.Treemap
|> Chart.WithOptions options
|> Chart.WithLabels
[
"Location"
"Parent"
"Market trade volume (size)"
"Market increase/decrease (color)"
]
|> Chart.Show

Related

Why is MediumTopAppBar (and Large) showing two TextField in compose?

I am trying to make the title of a screen editable.
MediumTopAppBar(
title = {
val name: String? = "Some Title"
var input by remember { mutableStateOf(name ?: "") }
when (state.isEditingTitle) {
true ->
TextField(
value = input,
onValueChange = { input = it },
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {
callbacks.onEditTitleChange(editTitle = false, updatedTitle = input)
})
)
false -> {
Text(
modifier = Modifier.clickable { callbacks.onEditTitleChange(true, null) },
text = name ?: "(No Title)"
)
}
}
},
... more app bar parameters
}
When I click on the title Text(...) and the view gets recomposed the AppBar shows two TextFields
How do I ignore the top one and only show the one in the bottom, like the Text() is only shown in the bottom?
(Fyi: the two TextInputs have their own remembered state and calls the callback with their own respective value)
Bonus question: How do I handle the remembered state "input" so that it resets every time the onDone keyboard action is triggered? Instead of val name: String? = "Some Title" it would of course be something in the line of val name: String? = state.stateModel.title
I found out why it does this, but I have no idea how to solve it (except for just making my own views and placing it close by)
It's easy to see when looking at the function for the MediumTopBar
// androidx.compose.material3.AppBar.kt
#ExperimentalMaterial3Api
#Composable
fun MediumTopAppBar(
title: #Composable () -> Unit,
modifier: Modifier = Modifier,
navigationIcon: #Composable () -> Unit = {},
actions: #Composable RowScope.() -> Unit = {},
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
colors: TopAppBarColors = TopAppBarDefaults.mediumTopAppBarColors(),
scrollBehavior: TopAppBarScrollBehavior? = null
) {
TwoRowsTopAppBar(
modifier = modifier,
title = title,
titleTextStyle = MaterialTheme.typography.fromToken(TopAppBarMediumTokens.HeadlineFont),
smallTitleTextStyle = MaterialTheme.typography.fromToken(TopAppBarSmallTokens.HeadlineFont),
titleBottomPadding = MediumTitleBottomPadding,
smallTitle = title, // <- this thing, right here
navigationIcon = navigationIcon,
actions = actions,
colors = colors,
windowInsets = windowInsets,
maxHeight = TopAppBarMediumTokens.ContainerHeight,
pinnedHeight = TopAppBarSmallTokens.ContainerHeight,
scrollBehavior = scrollBehavior
)
}
There's some internal state shenanigans going on, probably checking for a Text being shown in the 2nd TopAppBarLayout (more digging required to find that), but not for any other view.
TwoRowsTopAppBar and TopAppBarLayout are not public, and can't be used directly.
This is explains why, but it would be interesting to see how to solve it (still using Medium or Large -TopAppBar)
it is stupid thing devs overlooked and should be warned against, at least. The answer is do not give default colors to your Typography TextStyles.
private val BodySmall = TextStyle(
fontSize = 10.sp,
lineHeight = 12.sp,
fontWeight = FontWeight.SemiBold,
fontFamily = Manrope,
color = Color.Black // REMOVE THIS
)
val OurTypography = Typography(
...
bodySmall = BodySmall
)

Event to capture unselect category

I am using highcharter library. I want to split (or filter) other charts and tables based on selection in particular category of pie (doughnut) chart. My below code is working fine.
Desired result - When user clicks on pie again after selection, it should remove filtering. Below code captures last clicked category and it matches with the current selection using curre() and lstre() reactive values.
Issue When user clicks on pie more than twice, last clicked category matches with the current selected category so it does not perform any filtering.
I tried hc_add_event_point(event = "unselect"), it does not let user select particular category of pie more than twice.
library("shiny")
library("highcharter")
library(dplyr)
ui <- shinyUI(
fluidPage(
column(width = 8, highchartOutput("hcontainer", height = "500px")),
column(width = 4, textOutput("text")),
column(width = 4, dataTableOutput('temptable')))
)
server <- function(input, output) {
a <- data.frame(b = LETTERS[1:5], c = 11:15)
aa <- data.frame(b = LETTERS[1:5])
output$hcontainer <- renderHighchart({
canvasClickFunction <- JS("function(event) {Shiny.setInputValue('canvasClicked', [this.name, event.point.name, Math.random()]);}")
legendClickFunction <- JS("function(event) {Shiny.setInputValue('legendClicked', this.name);}")
highchart() %>%
hc_chart(type="pie") %>%
hc_add_series_labels_values(labels = a$b, values = a$c,
innerSize = '60%',
allowPointSelect= TRUE,
slicedOffset = 20,
states = list(
select = list(
color= NULL,
borderWidth = 5,
borderColor = '#ccc'
))) %>%
hc_plotOptions(series = list(
events = list(click = canvasClickFunction,
legendItemClick = legendClickFunction))) %>%
hc_add_event_point(event = "unselect")
})
makeReactiveBinding("outputText")
rv <- reactiveValues(lstval=0,curval=0)
observeEvent(input$canvasClicked[2], {
rv$lstval <- rv$curval;
rv$curval <- input$canvasClicked[2]}
)
curre <- reactive({req(input$canvasClicked[2]); input$canvasClicked[2]; rv$curval})
lstre <- reactive({req(input$canvasClicked[2]); input$canvasClicked[2]; rv$lstval})
observeEvent(input$canvasClicked, {
outputText <<- paste0("You clicked on series ", input$canvasClicked[1], " and the bar you clicked was from category ", input$canvasClicked[2],
input$plot_hc_unselect, ".")
})
observeEvent(input$legendClicked, {
outputText <<- paste0("You clicked into the legend and selected series ", input$legendClicked, ".")
})
output$text <- renderText({
outputText
})
output$temptable <- renderDataTable(
if (length(input$canvasClicked[2])>0) {
if (curre()!=lstre())
aa %>% filter(b==input$canvasClicked[2])
else {
aa
}
}
else {aa}
)
}
shinyApp(ui, server)

How to set certain columns to Bubble Chart dataLabel in highcharts (Rcharts)?

How to set "prd_nm" column to bubble chart's data label?
I try to use "plot Options : format" option, but i can't find it.
data <- top30
colnames(data) <- c('prd_rk', 'prd_nm', 'category', 'strategy', 'plc',
'sales', 'purchases', 'customers', 'age', 'purchase_rate',
'repurchase_rate')
hc <- hPlot(sales ~ purchases, data = data, type = "bubble", size =
"customers", group = "strategy")
hc$plotOptions(series=list(dataLabels=list(enabled=TRUE, formmat= .
{"y"})))
hc$set(height = 500)
hc$colors(palette)
hc
You have a little typo there with formmat. Please try to change your code to:
hc$plotOptions(series=list(dataLabels=list(enabled=TRUE, format="{prd_nm}")))

Are options and WithSize etc in XPlot specific to only certain charts?

I've tried Chart.WithSize and displayZoomButtons = true in the FSLab tutorial, but nothing seems to change the output.
Same thing in other projects using XPlot.GoogleCharts directly.
Am I missing something?
Download Plotly 1.4.2 from nuget and replace the dlls in the FSLab packages directory for XPlotly (see Plotting with Xplotly Q). Then you can use Xplotly's controls to zoom in and out, save the chart, etc. For example:
#load #"..\..\FSLAB\packages\FsLab\FsLab.fsx"
open XPlot.Plotly
open XPlot.Plotly.Graph
open XPlot.Plotly.Html
//open XPlot.GoogleCharts
let layout = Layout(title = "Basic Bar Chart")
["giraffes", 20; "orangutans", 14; "monkeys", 23]
|> Chart.Bar
|> Chart.WithLayout layout
|> Chart.WithHeight 400
|> Chart.WithWidth 700
|> Chart.Show
Very barebones charting solution using Plotly (and it works):
open Newtonsoft.Json
let html = """<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv" style="width: 100%; height: 100%;"></div>
<script>
var data = __DATA__;
var layout = __LAYOUT__;
Plotly.newPlot('myDiv', data, layout);
</script>
</body>"""
let (=>) k v = k, (v:>obj)
let doPlot data layout =
let data = JsonConvert.SerializeObject data
let layout = JsonConvert.SerializeObject layout
let path = Path.GetTempPath() + DateTime.Now.Ticks.ToString() + ".html"
File.WriteAllText(path, html.Replace("__DATA__", data).Replace("__LAYOUT__", layout))
System.Diagnostics.Process.Start(path)
let layout =
[ "title" => "Plot"
"xaxis" => dict [
"title" => "Ticks"
"showgrid" => false
"zeroline" => false
]
"yaxis" => dict [
"title" => "Price"
"showline" => false
]
] |> dict
let data = [
dict [ "x" => [1999; 2000; 2001; 2002]
"y" => [16; 5; 11; 9]
]
]
doPlot data layout

Highcharts bar chart with varied bar widths?

I want to make stacked bar chart where each portion has a width that encodes one value (say "Change" in the data below) and a height that encodes another value ("Share")
In some ways this is like a histogram with different bin sizes. There are a few "histogram" questions but none seem to address this. Plot Histograms in Highcharts
So given data like this:
Category Share Price Change
Apples 14.35 0.1314192423
Horseradish 46.168 0.1761474117
Figs 2.871 0.018874249
Tomatoes 13.954 0.0106121298
Mangoes 7.264 0.1217297011
Raisins 5.738 0.0206787136
Eggplant 6.31 0.0110160732
Other produce 3.344 0.0945377722
I can make a stacked bar that captures the "share" column in widths:
And another that captures the "change" column in heights:
And I can use an image editor to combine those into this histogram-like beast:
Which really captures that horseradish is a huge deal. So my question is, can I do that within Highcharts?
You can realise that by using snippet.
(function (H) {
var seriesTypes = H.seriesTypes,
each = H.each,
extendClass = H.extendClass,
defaultPlotOptions = H.getOptions().plotOptions,
merge = H.merge;
defaultPlotOptions.marimekko = merge(defaultPlotOptions.column, {
pointPadding: 0,
groupPadding: 0
});
seriesTypes.marimekko = extendClass(seriesTypes.column, {
type: 'marimekko',
pointArrayMap: ['y', 'z'],
parallelArrays: ['x', 'y', 'z'],
processData: function () {
var series = this;
this.totalZ = 0;
this.relZ = [];
seriesTypes.column.prototype.processData.call(this);
each(this.zData, function (z, i) {
series.relZ[i] = series.totalZ;
series.totalZ += z;
});
},
translate: function () {
var series = this,
totalZ = series.totalZ,
xAxis = series.xAxis;
seriesTypes.column.prototype.translate.call(this);
// Distort the points to reflect z dimension
each(this.points, function (point, i) {
var shapeArgs = point.shapeArgs,
relZ = series.relZ[i];
shapeArgs.x *= (relZ / totalZ) / (shapeArgs.x / xAxis.len);
shapeArgs.width *= (point.z / totalZ) / (series.pointRange / series.xAxis.max);
});
}
});
}(Highcharts));
Example: http://jsfiddle.net/highcharts/75oucp3b/

Resources