#dashapp.callback(
Output(component_id='data-storage', component_property='data'),
Input(component_id='input', component_property='n_submit')
.
.
.
return json_data
#dashapp.callback(
Output('table', component_property='columns'),
Output('table', component_property='data'),
Output('table', component_property='style_cell_conditional'),
Input(component_id='data-storage', component_property='data'),
.
.
.
column_name = 'Target Column'
value = 'This value is a string'
table_columns = [{"name": i, "id": i} for i in df.columns]
table_data = df.to_dict("records")
conditional_formatting = [{
'if': {
'filter_query': f'{{{column_name}}} = {value}'
},
'backgroundColor': 'white',
'color' : 'black',
}
]
return table_columns, table_data, conditional_formatting
When the code above is used WITH the conditional_formatting part - it works for some 'value's, and does not work for other 'value's
When the code above is used WITHOUT the conditional_formatting part - it works as expected for all 'value's
To be noted that when the conditional_formatting part is used, all callbacks are triggered twice. After this happens, the Data Store acts as if it has been infected by the "sick" value and does not allow new data.
Example:
Step 1. Use working input -> All callbacks triggered once -> Data Store is populated -> Data is displayed as expected
Step 2. Use working input -> All callbacks triggered once -> Data Store is populated -> Data is displayed as expected
Step 3. Use not working input -> All callbacks triggered once -> All callbacks are triggered again -> Data related to Input from b) is displayed
Step 4. Use working input -> All callbacks triggered once -> All callbacks are triggered again -> Data related to Input from b) is displayed
Any ideas why does this happen?
Any feedback is appreciated!
conditional_formatting = [{
'if': {
'filter_query': f'{{{column_name}}} = "{value}"'
},
'backgroundColor': 'white',
'color' : 'black',
}
]
Issue was because the failing values had empty space (e.g. San Francisco). Adding quotes around solved the issue.
Related
I'm looking for a way to make streams that are combined
Note: this is the simplest form of my problem, in reality I'm combining 8 different streams some are intertwined, some are async etc :(
import { BehaviorSubject, map, combineLatest } from 'rxjs';
const $A = new BehaviorSubject(1)
const $B = $A.pipe(map(val => `$B : ${val}`))
const $C = $A.pipe(map(val => `$C : ${val}`))
// prints out:
// (1) [1, "$B : 1", "$C : 1"]
combineLatest([$A,$B,$C]).subscribe(console.log)
$A.next(2)
// prints out:
// (2) [2, "$B : 1", "$C : 1"]
// (3) [2, "$B : 2", "$C : 1"]
// (4) [2, "$B : 2", "$C : 2"]
Code example
The print out (1) is great, all streams have a value of "1": [1, "$B : 1", "$C : 1"]
The print out (4) is great, all streams have a value of "2": [2, "$B : 2", "$C : 2"]
But the combine latest fires for (2) and (3) after each stream is updated individually meaning that you have a mixture of "1" and "2"
**What way can I modify the code to only get notified when a change has fully propgaged? **
My best solutions so far:
A) using debouceTime(100)
combineLatest([$A,$B,$C]).pipe(debounceTime(100)).subscribe(console.log)
But it's flaky because it can either swallow valid states if the are process to quickly or notify with invalid states if individual pipes are too slow
B) filter only valid state
combineLatest([$A,$B,$C]).pipe(
filter(([a,b,c])=>{
return b.indexOf(a) > -1 && c.indexOf(a) > -1
})
).subscribe(console.log)
works but adding a validation function seems like the wrong way to do it (and more work :))
C) Make B$ and C$ in which we push the latest and reset at every change"
A$.pipe(tap(val)=>{
B$.next(undefined);
B$.next(val);
C$.next(undefined)
C$.next(val);
})
...
combineLatest([$A,$B.pipe(filter(b => !!b)),$C.pipe(filter(c => !!c))]).pipe(
filter(([a,b,c])=>{
return b.indexOf(a) > -1 && c.indexOf(a) > -1
})
Works but quite a lot of extra code and vars
I have the feeling I'm missing a concept or not seeing how to achieve this in a clean/robust way, but I sure I'm not the first one :)
Thanks
As you've observed, the observable created by combineLatest will emit when any of its sources emit.
Your problem is occurring because you pass multiple observables into combineLatest that share a common source. So whenever that common source emits, it causes each derived observable to emit.
One way to "fix" this in a synchronous scenario is to simply apply debounceTime(0) which will mask the duplicate emission that happens in the same event loop. This approach is a bit naive, but works in simple scenarios:
combineLatest([$A,$B,$C]).pipe(
debounceTime(0)
)
But, since you have some async things going on, I think your solution is to not include duplicate sources inside combineLatest and handle the logic further down the chain:
combineLatest([$A]).pipe(
map(([val]) => [
val,
`$B : ${val}`,
`$C : ${val}`,
])
)
The code above produces the desired output. Obviously, you wouldn't need combineLatest with a single source, but the idea is the same if you had multiple sources.
Let's use a more concrete example that has the same issue:
const userId$ = new ReplaySubject<string>(1);
const maxMsgCount$ = new BehaviorSubject(2);
const details$ = userId$.pipe(switchMap(id => getDetails(id)));
const messages$ = combineLatest([userId$, maxMsgCount$]).pipe(
switchMap(([id, max]) => getMessages(id, max))
);
const user$ = combineLatest([userId$, details$, messages$]).pipe(
map(([id, details, messages]) => ({
id,
age: details.age,
name: details.name,
messages
}))
);
Notice when userId emits a new value, the user$ observable would end up emitting values that had the new userId, but the details from the old user!
We can prevent this by only including unique sources in our combineLatest:
const userId$ = new ReplaySubject<string>(1);
const maxMsgCount$ = new BehaviorSubject(2);
const user$ = combineLatest([userId$, maxMsgCount$]).pipe(
switchMap(([id, max]) => combineLatest([getDetails(id), getMessages(id, max)]).pipe(
map(([details, messages]) => ({
id,
age: details.age,
name: details.name,
messages
}))
))
);
You can see this behavior in action in the below stackblitz samples:
Problem
Solution
I want to create a binding of the Plotly.js library to Fable.
I am looking at this js code
import React from 'react';
import Plot from 'react-plotly.js';
class App extends React.Component {
render() {
return (
<Plot
data={[
{
x: [1, 2, 3],
y: [2, 6, 3],
type: 'scatter',
mode: 'lines+points',
marker: {color: 'red'},
},
{type: 'bar', x: [1, 2, 3], y: [2, 5, 3]},
]}
layout={ {width: 320, height: 240, title: 'A Fancy Plot'} }
/>
);
}
}
and my (faulty) attempt of creating a simple test binding looks like this
open Fable.Core
open Fable.Core.JsInterop
open Browser.Types
open Fable.React
// module Props =
type Chart =
|X of int list
|Y of int List
|Type of string
type IProp =
| Data of obj list
let inline plot (props: IProp) : ReactElement =
ofImport "Plot" "react-plotly.js" props []
let myTrace = createObj [
"x" ==> [1,2,3]
"y" ==> [2,6,3]
"type" ==> "scatter"
"mode" ==> "lines"
]
let myData = Data [myTrace]
let testPlot = plot myData
But obviously it does not work. How do I get it to work? Also, what does {[...]} mean? I am new to Javascript, and as far as I know {...} denotes an object which must contain name value pairs, and [...] denotes an array. So {[...]} seems to denote an object with a single nameless member that is an array, but as far as I know, there are no objects with nameless members.
I have been able to reproduce the example you linked. Please note that I don't Plotly and that I went the empiric way and so things can probably be improved :)
I have created the code as I would probably have done it if I had to use it in my production app. So there is a bit more code than in your question because I don't use createObj.
If you don't like the typed DSL you can always simplify it, remove it and use createObj or anonymous record like I did for the marker property :)
You need to install both react-plotly.js plotly.js in your project.
open Fable.Core.JsInterop
open Fable.Core
open Fable.React
// Define props using DUs this helps create a typed version of the React props
// You can then transform a list of props into an object using `keyValueList`
[<RequireQualifiedAccess>]
type LayoutProps =
| Title of string
| Width of int
| Height of int
// GraphType is marked as a `StringEnum` this means
// the value will be replace at compile time with
// their string representation so:
// `Scatter` becomes `"scatter"`
// You can customise the output by using `[<CompiledName("MyCustomName")>]
[<RequireQualifiedAccess; StringEnum>]
type GraphType =
| Scatter
| Bar
[<RequireQualifiedAccess; StringEnum>]
type GraphMode =
| Lines
| Points
| Markers
| Text
| None
[<RequireQualifiedAccess>]
type DataProps =
| X of obj array
| Y of obj array
| Type of GraphType
| Marker of obj
// This is an helpers to generate the `flagList` waited by Plotly, if you don't like it you can just remove
// member and replace it with `| Mode of string` and so you have to pass the string by yourself
static member Mode (modes : GraphMode seq) : DataProps =
let flags =
modes
|> Seq.map unbox<string> // This is safe to do that because GraphMode is a StringEnum
|> String.concat "+"
unbox ("mode", flags)
[<RequireQualifiedAccess>]
type PlotProps =
| Nothing // Should have real props here is there exist more than Data and Layout
// Here notes that we are asking for an `Array` or Data
// Array being the type expected by the JavaScript library
// `DataProps seq` is our way to represents props
static member Data (dataList : (DataProps seq) array) : PlotProps =
let datas =
dataList
|> Array.map (fun v ->
keyValueList CaseRules.LowerFirst v // Transform the list of props into a JavaScript object
)
unbox ("data", datas)
static member Layout (props : LayoutProps seq) : PlotProps =
unbox ("layout", keyValueList CaseRules.LowerFirst props)
// All the example I saw from react-plotly was using this factory function to transform the plotly library into a React component
// Even, the example you shown if you look at the Babel tab in the live example
let createPlotlyComponent (plotly : obj) = import "default" "react-plotly.js/factory"
// Immport the plotly.js library
let plotlyLib : obj = import "default" "plotly.js"
// Apply the factory on the plotly library
let Plot : obj = createPlotlyComponent plotlyLib
// Helper function to instantiate the react components
// This is really low level, in general we use `ofImport` like you did but if I use `ofImport` then I got a React error
let inline renderPlot (plot : obj) (props : PlotProps list) =
ReactBindings.React.createElement(plot, (keyValueList CaseRules.LowerFirst props), [])
let root =
// Here we can render the plot using our Typed DSL
renderPlot
Plot
[
PlotProps.Data
[|
[
DataProps.X [| 1; 2; 3 |]
DataProps.Y [| 2; 6; 3 |]
DataProps.Type GraphType.Scatter
DataProps.Mode
[
GraphMode.Lines
GraphMode.Points
]
DataProps.Marker {| color = "red" |}
]
[
DataProps.Type GraphType.Bar
DataProps.X [| 1; 2; 3 |]
DataProps.Y [| 2; 5; 3 |]
]
|]
PlotProps.Layout
[
LayoutProps.Width 640
LayoutProps.Height 480
LayoutProps.Title "A Fancy Plot"
]
]
I'm a bit late to the party here, but wanted to give you a different option if you're still looking to use plotly.js with Fable.
I've been working on bindings for plotly.js for the past month or so, and it's in a pretty usable state as of now. That being said, I wouldn't say it's production ready.
This is what the example you want to convert would look like written with Feliz.Plotly:
open Feliz
open Feliz.Plotly
let chart () =
Plotly.plot [
plot.traces [
traces.scatter [
scatter.x [ 1; 2; 3 ]
scatter.y [ 2; 6; 3 ]
scatter.mode [
scatter.mode.lines
scatter.mode.markers
]
scatter.marker [
marker.color color.red
]
]
traces.bar [
bar.x [ 1; 2; 3 ]
bar.y [ 2; 5; 3 ]
]
]
plot.layout [
layout.width 320
layout.height 240
layout.title [
title.text "A Fancy Plot"
]
]
]
You can find more information out here.
I have made an interactive choropleth map with bokeh, and I'm trying to add active interactions using the dropdown widget (Select). However, most tutorials and SO questions about active interactions use ColumnDataSource, and not GeoJSONDataSource.
The issue is that GeoJSONDataSource doesn't have a .data method like ColumnDataSource does, so idk exactly how the syntax works when updating it.
My dataset is a dictionary in the form of city_dict = {'Amsterdam': <some data frame>, 'Antwerp': <some data frame>, ...}, where the dataframe is in geojson format. I have already confirmed that this format works when making glyphs.
def update(attr, old, new):
s_value = dropdown.value
p.title.text = '%s', s_value
new_src1 = make_dataset(s_value)
val1 = GeoJSONDataSource(new_src1)
r1.data_source = val1
where make_dataset is a function that transforms my original dataset into a dataset that can feed into the GeoJSONDataSource function. make_dataset requires a string (name of the city) to work eg. 'Amsterdam'. It works on passive interactions.
The main plot code (removed unnecessary stuff) is:
dropdown = Select(value='Amsterdam', options = cities)
controls = WidgetBox(dropdown)
initial_city = 'Amsterdam'
a = make_dataset(initial_city)
src1 = GeoJSONDataSource(a)
p = figure(title = 'Amsterdam', plot_height = 750 , plot_width = 900, toolbar_location = 'right')
r1 = p.patches('xs','ys', source = src1, fill_color = {'field' :'norm', 'transform' : color_mapper})
dropdown.on_change('value', update)
layout = row(controls, p)
curdoc().add_root(layout)
I've added the error I get. error handling message Message 'PATCH-DOC' (revision 1) content: {'events': [{'kind': 'ModelChanged', 'model': {'type': 'Select', 'id': '1147'}, 'attr': 'value', 'new': 'Antwerp'}], 'references': []}: ValueError("expected a value of type str, got ('%s', 'Antwerp') of type tuple",)
Let's assume that I use the default pyramid UnencryptedCookieSessionFactory
...
my_session_factory = UnencryptedCookieSessionFactoryConfig('itsaseekreet')
config = Configurator(settings=settings)
config.set_session_factory(my_session_factory)
...
and define two views with a link to each other:
#view_config(route_name='t1')
def t1(request):
session = request.session
session['fred'] = '***'
session['abc'] = '&&&'
return Response(str(session.__dict__) + 't2')
#view_config(route_name='t2')
def t2(request):
session = request.session
return Response(str(session.__dict__) + 't1')
If I visit t1 in browser I get the following output:
{'accessed': 1377760577, '_dirty': True, 'request': , 'new': False, 'created': 1377760540.30155}t2
and if i follow the link to t2:
{'accessed': 1377760577, 'request': , 'new': False, 'created': 1377760540.30155}t1
But I would expect something different for t1 and t2:
{ ..., 'fred': '***', 'abc': '&&&', ...}
Why are the values not stored in the session? And what does the _dirty flag mean?
session.__dict__ is not the api for dealing with sessions. The session underneath is implemented as a dict object which does not use __dict__ to store its contents. You're simply printing out the attributes on the class which are unrelated. Print out something like session.items() instead or just session since its a dict.
I have a task to match multiple events(facts) with each other by some their properties.
As a result of events matching some action should be generated. Action can be generated when events of all exists types were matched.
Is there any algorithm which could be used for such task? Or any direction?
Thanks
Example:
We have several events with different types and properties.
Type SEEN is cumulative event (several events could be merged for matching) and type FOUND is not.
Event 1 (SEEN):
DATE="2009-09-30"
EYES_COLOR="BLUE"
LEFT_SOCK_COLOR="RED"
Event 2 (SEEN):
DATE="2009-09-30"
EYES_COLOR="BLUE"
RIGHT_SOCK_COLOR="GREEN"
Event 3 (FOUND):
DATE="2009-09-30"
EYES_COLOR="BLUE"
LEFT_SOCK_COLOR="BLUE"
RIGHT_SOCK_COLOR="GREEN"
PLACE="MARKET"
Event 4 (FOUND):
DATE="2009-09-30"
EYES_COLOR="BLUE"
LEFT_SOCK_COLOR="GREEN"
PLACE="SHOP"
Event 5 (FOUND):
DATE="2009-09-30"
EYES_COLOR="BLUE"
PLACE="AIRPORT"
For above events such actions should be generated (by composing matched events):
Action 1_2_3:
DATE="2009-09-30"
EYES_COLOR="BLUE"
LEFT_SOCK_COLOR="RED"
RIGHT_SOCK_COLOR="GREEN"
PLACE="MARKET"
Action 2_4:
DATE="2009-09-30"
EYES_COLOR="BLUE"
LEFT_SOCK_COLOR="GREEN"
PLACE="SHOP"
Means:
Event 1 + Event 2 + Event 3 => Action 1_2_3
Event 2 + Event 4 => Action 2_4
Event 5 does not match with anything.
in your case every two events are either compatible or not; we can denote this by C(e,e'), meaning that event e is compatible with event e'. You can build a maximal set of compatible events of course iteratively; when you have a set {e1,e2,...,en} of compatible events, you can add e' to the set if and only if e' is compatible with every e1,...,en, i.e. C(ei,e') is true for all 1<=i<=n.
Unfortunately in your case the number of maximal sets of compatible events can be exponential to the number of events, because you can have e.g. events e1, e2, e3 and e4 so that they are all pair-wisely compatible but none of them is compatible with TWO other events; for this set you will already get 6 different "actions", and they overlap each other.
A simple algorithm is to have a recursive search where you add events one by one to the prospectual "action", and when you can't add any more events you register the action; then you backtrack. It's called "backtracking search". You can improve its running time then by proper datastructures for "quickly" looking up the matching events.
As in the comment, the question about SEEN/FOUND is open; I'm assuming here that the fields are merged "as is".
This pseudo-code may help: (C# syntax)
foreach (var found in events.Where(x => x.EventType == "Found"))
{
var matches = events.Where(x => x.EventType == "Seen"
&& x.Whatever == found.Whatever);
if (matches.Count() > 0)
{
// Create an action based on the single "Found" event
// and the multiple matching "Seen" events.
}
}
I'm not sure I understand the question correctly. It seems that for every FOUND event, you want to identify all matching SEEN events and merge them? Python code:
# assume events are dictionaries, and you have 2 lists of them by type:
# (omitting DATE because it's always "2009-09-03" in your example)
seen_events = [
{
"EYES_COLOR": "BLUE",
"LEFT_SOCK_COLOR": "RED",
},
{
"EYES_COLOR": "BLUE",
"RIGHT_SOCK_COLOR": "GREEN",
},
]
found_events = [
{
"EYES_COLOR": "BLUE",
"LEFT_SOCK_COLOR": "BLUE",
"RIGHT_SOCK_COLOR": "GREEN",
"PLACE": "MARKET",
},
{
"EYES_COLOR": "BLUE",
"LEFT_SOCK_COLOR": "GREEN",
"PLACE": "SHOP",
},
{
"EYES_COLOR": "BLUE",
"PLACE": "AIRPORT",
},
]
def do_action(seen_events, found):
"""DUMMY"""
for seen in seen_events:
print seen
print found
print
# brute force
for found in found_events:
matching = []
for seen in seen_events:
for k in found:
if k in seen and seen[k] != found[k]:
break
else: # for ended without break (Python syntax)
matching.append(seen)
if matching:
do_action(matching, found)
which prints:
{'EYES_COLOR': 'BLUE', 'RIGHT_SOCK_COLOR': 'GREEN'}
{'EYES_COLOR': 'BLUE', 'PLACE': 'MARKET', 'LEFT_SOCK_COLOR': 'BLUE', 'RIGHT_SOCK_COLOR': 'GREEN'}
{'EYES_COLOR': 'BLUE', 'RIGHT_SOCK_COLOR': 'GREEN'}
{'EYES_COLOR': 'BLUE', 'PLACE': 'SHOP', 'LEFT_SOCK_COLOR': 'GREEN'}
{'EYES_COLOR': 'BLUE', 'LEFT_SOCK_COLOR': 'RED'}
{'EYES_COLOR': 'BLUE', 'RIGHT_SOCK_COLOR': 'GREEN'}
{'EYES_COLOR': 'BLUE', 'PLACE': 'AIRPORT'}
Right, this is not effecient - O(n*m) - but does this even describe the problem correctly?