I am stuck with some data manipulation.
This is a small portion of the input data (df):
site=c("C000-C002","C420-C421,C424")
histology=c("9835-9836","9811-9812,9837")
category=c("Leukemia","Leukemia")
df=data.frame(site,histology,category)
And this is what I want the processed data to look like:
You may assume Site and Histology are both 4-digit after text splitting.
In case anyone is interested, the full data table is here
Please help with the text processing, or if anyone knows an existing processed package or database in a similar format as the image, that would be great too.
Thank you very much.
I don't know R language. So I tried with Javascript as following.
function mapStartEnd(start, end) {
let list = [];
let info = {};
const siteStart = start.match(/([A-Z])(\d{3})/);
if (siteStart) {
const siteEnd = end.match(/([A-Z])(\d{3})/);
info = {
type: "site",
prefix: siteStart[1],
numLength: 3,
from: parseInt(siteStart[2], 10),
to: parseInt(siteEnd[2], 10),
};
}
const histologyStart = start.match(/\d{4}/);
if (histologyStart) {
const histologyEnd = end.match(/\d{4}/);
info = {
type: "histology",
prefix: "",
numLength: 4,
from: parseInt(histologyStart[0], 10),
to: parseInt(histologyEnd[0], 10),
};
}
const categoryStart = start.match(/[A-Z][a-z]+/);
if (categoryStart) {
const categoryEnd = end.match(/[A-Z][a-z]+/);
info = {
type: "category",
prefix: "",
numLength: 0,
from: categoryStart[0],
to: categoryEnd[0],
};
}
if (!info.numLength) {
list = [info.from, info.to];
} else {
for (let i = info.from; i <= info.to; i++) {
list.push(info.prefix + i.toString().padStart(info.numLength, "0"));
}
}
return list;
}
function c(list) {
return list.map((list2) => {
return list2.split(",").reduce((prev, cur) => {
const [start, end] = cur.split("-");
if (!end) prev.push(start);
else prev = [...prev, ...mapStartEnd(start, end)];
return prev;
}, []);
});
}
function map3(sites, histologys, categorys) {
let list = [];
for (let i = 0; i < sites.length; i++) {
const site = sites[i];
for (let j = 0; j < histologys.length; j++) {
const histology = histologys[j];
for (let k = 0; k < categorys.length; k++) {
const category = categorys[k];
// JSON format
// list.push({ site, histology, category });
// CSV format
list.push(`${site},${histology},${category}`);
}
}
}
return list;
}
function frame(sites, histologys, categorys) {
let list = [];
for (let i = 0; i < sites.length; i++) {
const site = sites[i];
const histology = histologys[i];
const category = categorys[i];
list = [...list, ...map3(site, histology, category)];
}
return list;
}
const site = c(["C000-C002", "C420-C421,C424"]);
const histology = c(["9835-9836", "9811-9812,9837"]);
const category = c(["Leukemia", "Leukemia"]);
const df = frame(site, histology, category);
console.log(df);
Result:
[
"C000,9835,Leukemia",
"C000,9836,Leukemia",
"C001,9835,Leukemia",
"C001,9836,Leukemia",
"C002,9835,Leukemia",
"C002,9836,Leukemia",
"C420,9811,Leukemia",
"C420,9812,Leukemia",
"C420,9837,Leukemia",
"C421,9811,Leukemia",
"C421,9812,Leukemia",
"C421,9837,Leukemia",
"C424,9811,Leukemia",
"C424,9812,Leukemia",
"C424,9837,Leukemia"
]
https://jsfiddle.net/dnu2g0vr/
Related
I am able to export a list of JSON objects to an excel file using sheetjs in angular. One of the requirements is, user should be able to sort and filter the date fields like below.
But as you can see, along with the date part, the time part also comes while filtering. Is there a way, I can remove the time part and still be able to do the filtering like above?
Here is my code.
exportToExcel(arrData: any[], fileName: string, formattingData: ExcelFormattingData = undefined) {
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(arrData, {cellDates: true, dateNF: this.userAuthToken.dateFormat});
if(formattingData != null) {
const range = XLSX.utils.decode_range(worksheet['!ref']);
for (let j = range.s.c; j <= range.e.c; j++) {
let ref_columnHeader = XLSX.utils.encode_cell({r:range.s.r, c:j});
let columnName = worksheet[ref_columnHeader].v;
if(formattingData.Values.includes(columnName)){
for(let i = range.s.r + 1; i <= range.e.r; ++i) {
let ref = XLSX.utils.encode_cell({r:i, c:j});
if(worksheet[ref] != null) {
worksheet[ref].t = 'd';
worksheet[ref].z = formattingData.Format;
}
}
}
}
}
const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' });
FileSaver.saveAs(blob, fileName);
}
I'm trying another solution to my problem:
The thing is: im rendering a Sketch component with a background image and sketching over it
onReady = async () => {
const { layoutWidth, layoutHeight, points } = this.state;
this.sketch.graphics = new PIXI.Graphics();
const linesStored = this.props.screenProps.getSketchLines();
if (this.sketch.stage) {
if (layoutWidth && layoutHeight) {
const background = await PIXI.Sprite.fromExpoAsync(this.props.image);
background.width = layoutWidth * scaleR;
background.height = layoutHeight * scaleR;
this.sketch.stage.addChild(background);
this.sketch.renderer._update();
}
if (linesStored) {
for(let i = 0; i < linesStored.length; i++) {
this.sketch.stage.addChild(linesStored[i])
this.sketch.renderer._update();
}
}
}
};
this lineStored variable is returning a data i've saved onChange:
onChangeAsync = async (param) => {
const { uri } = await this.sketch.takeSnapshotAsync();
this.setState({
image: { uri },
showSketch: false,
});
if (this.sketch.stage.children.length > 0) {
this.props.screenProps.storeSketchOnState(this.sketch.stage.children);
}
this.props.callBackOnChange({
image: uri,
changeAction: this.state.onChangeAction,
startSketch: this.startSketch,
undoSketch: this.undoSketch,
});
};
storeSketchOnState saves this.sketch.stage.children; so when i change screen and back to the screen my Sketch component in being rendered, i can retrieve the sketch.stage.children from App.js state and apply to Sketch component to persist the sketching i was doing before
i'm trying to apply the retrieved data like this
if (linesStored) {
for(let i = 0; i < linesStored.length; i++) {
this.sketch.stage.addChild(linesStored[i])
this.sketch.renderer._update();
}
}
```
but it is not working =(
I want to retrieve the values of marked dates how can I get all the marked dates where marked value is true from this object:
alert(JSON.stringify(this.state._markedDates))
{"2018-09-26":{"marked":true}, "2018-09-27":{"marked":false}, "2018-09-29":{"marked":true}}
Expected Result :
{"2018-09-26","2018-09-29"}
I tried the following but datelist is still empty:
for(var i=0; i<this.state._markedDates.length ; i++)
{
if(this.state._markedDates[i].marked == true)
{
this.state.datesList.push(_markedDates[i])
}
}
let dates = {
"2018-09-26":{"marked":true},
"2018-09-27":{"marked":false},
"2018-09-29":{"marked":true}
}
let markedDates=[];
Object.keys(dates).map(date => {
if(dates[date].marked){ markedDates.push(date)}
})
console.log(markedDates)
There are different ways of approaching this, you could filter them for example as below:
let dates = ["2018-09-26":{"marked":true}, "2018-09-27":{"marked":false}, "2018-09-29":{"marked":true}];
let filtered = dates.filter( date => {
if(date.marked === true) {
return date;
}
});
// filtered = {"2018-09-26":{"marked":true}, "2018-09-29":{"marked":true}};
This is how you can get all of the dates where marked = true.
Then you can do
let keyNames = Object.keys(filtered);
console.log(keyNames); // Outputs ["2018-09-26","2018-09-29"]
As a for loop
let markedDates = [];
for(var i=0; i<this.state._markedDates.length; i++)
{
if(this.state._markedDates[i].marked === true)
{
markedDates.push(_markedDates[i])
}
}
this.setState({ObjectIWantToSet: markedDates})
let dates = []
let obj = {"2018-09-26":{"marked":true}, "2018-09-27":{"marked":false}, "2018-09-29":{"marked":true}}
for(date in obj)
{
if(a[date]["marked"])
{
dates.push(date)
}
}
console.log(dates)
I want to create a simple Tab but I think it is strange for my using:
var root = document.body
var index = {
view: () => index.html,
html: m('div', { id: 'div1' }, [
[
(function () {
let value = ["A", "B", "C", "D"]
let output = []
for (let i = 0; i < 4; i++) {
output.push(m('input', {
class: (function () {
if (i == 0) return "onit"
})(),
type: 'button',
value: value[i],
onclick: function () {
let div1 = document.getElementById("div1")
let btn = div1.getElementsByTagName("input")
let div1_div = div1.getElementsByTagName("div")
let _this = this
let num = (function () {
for (let i = 0; i < btn.length; i++) {
if (btn[i] == _this) {
return i
}
}
})()
for (let i = 0; i < btn.length; i++) {
btn[i].className = ""
}
this.className = "onit"
for (let i = 0; i < div1_div.length; i++) {
div1_div[i].setAttribute("style", "dispaly:none")
}
div1_div[num].setAttribute("style", "display:block")
}
}))
}
return output
})()
],
[
(function () {
let arr = ["aaa", "bbb", "ccc", "ddd"]
let output = []
for (let i = 0; i < 4; i++) {
output.push(m("div", { style: (the => i == 0 ? "display:block" : undefined)() }, arr[i]))
}
return output
})()
]
])
}
m.route(root, "/index", {
"/index": index
})
Is there any other simple way to achieve this?
If I click the button, the style of button will change and the display of all "div" will be changed. Screenshot
In mithril.js views you can only use expressions, for-loops, ifs and so on are no expressions and only possible the way you did it. Nevertheless there are other ways to achieve this
Loops can be achieved using the functional counterparts
let values = ["A", "B", "C", "D"]
let output = []
function(){
for (let i = 0; i < 4; i++) {
output.push(m('span', value)
}
return output
}()
can be written as
values.map(value => m('span', value)
if-Statements can be written using the ternary expression
function() {
if (condition) {
return 'this'
} else {
return 'that'
}
}()
just use
condition ? 'this' : 'that'
You can also use view functions if your view code gets to deeply nested and you need custom logic:
function someOtherView(someData) {
if (someData.shouldBeShown) {
return someData.text
}
}
function someView() {
...
someOtherView(someData)
...
}
This also makes your views more readable.
I'm trying to get the exchanges in ripple and I found this data API and its working. But I want to use the ripple websocket tool for some reasons. Is there any websocket equivalent for this data API?
I think there is equivalent if you use "tx_history" command in the socket but Sorry to tell you that the json result are not equal to your specific data result.
ripple data apiv2 is being played by ajax. see the result json formatter in ripple for exchange:
} else if (resp.rows.length) {
resp.rows[0] = {
base_currency: resp.rows[0].base_currency,
base_issuer: resp.rows[0].base_issuer,
base_amount: resp.rows[0].base_amount,
counter_amount: resp.rows[0].counter_amount,
counter_currency: resp.rows[0].counter_currency,
counter_issuer: resp.rows[0].counter_issuer,
rate: resp.rows[0].rate,
executed_time: resp.rows[0].executed_time,
ledger_index: resp.rows[0].ledger_index,
buyer: resp.rows[0].buyer,
seller: resp.rows[0].seller,
taker: resp.rows[0].taker,
provider: resp.rows[0].provider,
autobridged_currency: resp.rows[0].autobridged_currency,
autobridged_issuer: resp.rows[0].autobridged_issuer,
offer_sequence: resp.rows[0].offer_sequence,
tx_type: resp.rows[0].tx_type,
tx_index: resp.rows[0].tx_index,
node_index: resp.rows[0].node_index,
tx_hash: resp.rows[0].tx_hash
};
}
res.csv(resp.rows, filename);
} else {
res.json({
result: 'success',
count: resp.rows.length,
marker: resp.marker,
exchanges: resp.rows
});
} }
and it can be only access by get url :
route: '/v2/exchanges/{:base}/{:counter}'
that is bind in there server.js:
app.get('/v2/exchanges/:base/:counter', routes.getExchanges);
and last hint this is their database query using hbase:
HbaseClient.getExchanges = function (options, callback) {
var base = options.base.currency + '|' + (options.base.issuer || '');
var counter = options.counter.currency + '|' + (options.counter.issuer
||''); var table;
var keyBase;
var startRow;
var endRow;
var descending;
var columns;
if (counter.toLowerCase() > base.toLowerCase()) {
keyBase = base + '|' + counter;
} else {
keyBase = counter + '|' + base;
options.invert = true; }
if (!options.interval) {
table = 'exchanges';
descending = options.descending ? true : false;
options.unreduced = true;
//only need certain columns
if (options.reduce) {
columns = [
'd:base_amount',
'd:counter_amount',
'd:rate',
'f:executed_time',
'f:buyer',
'f:seller',
'f:taker'
];
}
} else if (exchangeIntervals.indexOf(options.interval) !== -1) {
keyBase = options.interval + '|' + keyBase;
descending = options.descending ? true : false;
table = 'agg_exchanges';
} else {
callback('invalid interval: ' + options.interval);
return; }
startRow = keyBase + '|' + options.start.hbaseFormatStartRow();
endRow = keyBase + '|' + options.end.hbaseFormatStopRow();
if (options.autobridged) {
options.filterstring = "DependentColumnFilter('f', 'autobridged_currency')";
if (columns) {
columns.push('f:autobridged_currency');
} }
this.getScanWithMarker(this, {
table: table,
startRow: startRow,
stopRow: endRow,
marker: options.marker,
limit: options.limit,
descending: descending,
columns: columns,
filterString: options.filterstring }, function (err, resp) {
if (!resp) {
resp = {rows: []};
}
if (!resp.rows) {
resp.rows = [];
}
if (options.reduce && options.unreduced) {
if (descending) {
resp.rows.reverse();
}
resp.reduced = reduce(resp.rows);
} else if (table === 'exchanges') {
resp.rows = formatExchanges(resp.rows);
} else {
resp.rows = formatAggregates(resp.rows);
}
callback(err, resp); });
/** * formatExchanges */
function formatExchanges (rows) {
rows.forEach(function(row) {
var key = row.rowkey.split('|');
delete row.base_issuer;
delete row.base_currency;
delete row.counter_issuer;
delete row.counter_currency;
row.base_amount = parseFloat(row.base_amount);
row.counter_amount = parseFloat(row.counter_amount);
row.rate = parseFloat(row.rate);
row.offer_sequence = Number(row.offer_sequence || 0);
row.ledger_index = Number(row.ledger_index);
row.tx_index = Number(key[6]);
row.node_index = Number(key[7]);
row.time = utils.unformatTime(key[4]).unix();
});
if (options.invert) {
rows = invertPair(rows);
}
return rows; }
/** * formatAggregates */
function formatAggregates (rows) {
rows.forEach(function(row) {
var key = row.rowkey.split('|');
row.base_volume = parseFloat(row.base_volume),
row.counter_volume = parseFloat(row.counter_volume),
row.buy_volume = parseFloat(row.buy_volume),
row.count = Number(row.count);
row.open = parseFloat(row.open);
row.high = parseFloat(row.high);
row.low = parseFloat(row.low);
row.close = parseFloat(row.close);
row.vwap = parseFloat(row.vwap);
row.close_time = Number(row.close_time);
row.open_time = Number(row.open_time);
});
if (options.invert) {
rows = invertPair(rows);
}
return rows; }
/** * if the base/counter key was inverted, we need to swap * some of the values in the results */
function invertPair (rows) {
var swap;
var i;
if (options.unreduced) {
for (i=0; i<rows.length; i++) {
rows[i].rate = 1/rows[i].rate;
//swap base and counter vol
swap = rows[i].base_amount;
rows[i].base_amount = rows[i].counter_amount;
rows[i].counter_amount = swap;
//swap buyer and seller
swap = rows[i].buyer;
rows[i].buyer = rows[i].seller;
rows[i].seller = swap;
}
} else {
for (i=0; i<rows.length; i++) {
//swap base and counter vol
swap = rows[i].base_volume;
rows[i].base_volume = rows[i].counter_volume;
rows[i].counter_volume = swap;
//swap high and low
swap = 1/rows[i].high;
rows[i].high = 1/rows[i].low;
rows[i].low = swap;
//invert open, close, vwap
rows[i].open = 1/rows[i].open;
rows[i].close = 1/rows[i].close;
rows[i].vwap = 1/rows[i].vwap;
//invert buy_volume
rows[i].buy_volume /= rows[i].vwap;
}
}
return rows; }
/** * reduce * reduce all rows */
function reduce (rows) {
var buyVolume = 0;
var reduced = {
open: 0,
high: 0,
low: Infinity,
close: 0,
base_volume: 0,
counter_volume: 0,
buy_volume: 0,
count: 0,
open_time: 0,
close_time: 0
};
rows = formatExchanges(rows);
// filter out small XRP amounts
rows = rows.filter(function(row) {
if (options.base.currency === 'XRP' && row.base_amount < 0.0005) {
return false;
} else if (options.counter.currency === 'XRP' && row.counter_amount < 0.0005) {
return false;
} else {
return true;
}
});
if (rows.length) {
reduced.open_time = moment.unix(rows[0].time).utc().format();
reduced.close_time = moment.unix(rows[rows.length-1].time).utc().format();
reduced.open = rows[0].rate;
reduced.close = rows[rows.length -1].rate;
reduced.count = rows.length;
} else {
reduced.low = 0;
return reduced;
}
rows.forEach(function(row) {
reduced.base_volume += row.base_amount;
reduced.counter_volume += row.counter_amount;
if (row.rate < reduced.low) reduced.low = row.rate;
if (row.rate > reduced.high) reduced.high = row.rate;
if (row.buyer === row.taker) {
reduced.buy_volume += row.base_amount;
}
});
reduced.vwap = reduced.counter_volume / reduced.base_volume;
return reduced; } };
Maybe you should make a custom websocket that make your RPC call upgrade to 1.1 http protocol (ws).
In nodejs you can simply
// for http
var http = require('http');
// for websocket
var ws = require("nodejs-websocket")
var options = {
host: 'URL-RPC-HERE',
port: '80',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
}
};
var req = http.request(options, function(res) {
// after getting the response wich is the <res>
// we can upgrade it to ws
upToWebsocket(res);
});
//Upgrade to websocket
var upToWebsocket = function(json) {
var server = ws.createServer(function (conn) {
conn.on("json", function (str) {
conn.sendText(str.toUpperCase()+"!!!")
})
conn.on("close", function (code, reason) {
console.log("Connection closed")
})
}).listen(8001)
}
And also if you have Rippled running on a server this does not help because there's no RPC or WS that supports exchange API.