Related
I have a contract that has to save the time and price of eth via chainlink. The time works and has no problems. The price, on the other hand, fails to be recorded either with an array or with a mapping. I have tried several solutions, which include push().
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
uint256 deadline;
uint256 startTime = startTimes[block.timestamp];
mapping(uint => uint) startTimes;
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
uint public ethPrice = 0;
uint256 price = ethPrice;
mapping(uint => uint) ethPrice;
function priceOnTime() public payable {
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
return ethPrice;
}
}
The chainLinkETHUSDAddress address hardcoded in your source contains a contract only on the Kovan testnet. Meaning, this code works only on this testnet or its forks, and fails on other networks.
If you want to use the returned value in Remix, you need to create a local fork of the Kovan testnet and then connect to this local network using the Environment selectbox in Remix.
Your code is not using the mapping correctly. I mapping is like an array, just more efficient in some ways, but also has some limitations.
so to use your mapping you need to use it as
ethPrice[x] = y;
Where both x and y are an uint (as you specified the mapping uint => uint). So each unique uint maps (refers) to another uint.
ethPrice[x] = uint(chainLinkEthPrice / 100000000);
Where x is an uint you use to lookup the value later on with.
You're incorrectly storing the mapping. Mapping has to be stored as variable[key]=value.
https://www.tutorialspoint.com/solidity/solidity_mappings.htm
When we use D3.js, let's say for simplicity, we have data, which are stock prices:
2021-03-18 $38.10
2021-03-19 $38.60
2021-03-22 $38.80
and we use D3 to plot a line chart for the stock price, and then move the mouse around to "hover" above the prices, and it'd show the price for that date.
Right now I am using
d3.select("svg").on("mousemove", (ev) => {
const hour = xScale.invert(ev.offsetX - dimensions.margin.left).getHours();
to get the hour of where the user is hovering on. The xScale is a scale function scaleTime() from domain to range, and xScale.invert is the function that convert the range back to domain.
If the hour is 12pm or later, I consider it the next day, and if it is before or equal, I consider it the same day. This is because the stock price of 2021-03-19 is considered to be at 12:00am (the midnight), so if I am getting to 9pm, for example, the mouse cursor is really close to the next day.
And then, let's say I identified that it is 2021-03-20, then I check whether there is stock price data. But since it was a Saturday and has no stock data, I use a function to check by the following method:
I first would go back to 2021-03-19 and see if there is a stock price. (I first build a lookup table to map date to data). If there is, then use it.
But if there isn't, I just use the delta of 1 day and move further and further, so it would go to 2021-03-21 and then increment the delta and use -delta to check for 2021-03-18, so I just use a point and go "later" and "before" with an increasing delta, until I am able to find a price
In other words, I have a "first candidate" and a "second candidate". If the first candidate has data, then use it. Otherwise, try the second candidate. If still not work, then work from the first candidate and use delta of 1 day and move "later" or "before", and if not work, use a delta of 2 days, and 3 days, until I am able to find a date with data.
Then I use this price to show on screen, to report what the date and price is
But this method is a bit low level. Does D3.js already have a method to directly do that: to spit out an invert number, which is closest to the key that has data in the dataset?
There are several functions provided by d3.js which can be used, depending on the exact situation:
1. You operate in screen space and want a mapping of the current mouse position on the closest point of the visualization which represents a single data object
In that case, you would probably want to use d3-delaunay.
d3-delaunay is a fast library for computing the Voronoi diagram of a
set of two-dimensional points. One can use delaunay.find to identify the data point closest to the pointer. Here is one example.
2. If you operate in the data domain (e.g. because you have already inverted the mouse position to the data domain)
As #Gerardo Furtado points out, you can use d3.bisect.
d3.bisect finds the position into which a given value can be inserted
into a sorted array while maintaining sorted order. If the value
already exists in the array, d3.bisect will find its position
efficiently. Here is one
example.
See also: D3: What is a Bisector? and d3.bisector using Date() Object does not resolve
Another option d3.js provides is d3.scaleThreshold.
Threshold scales allow you to map arbitrary subsets of the domain to discrete values in the range. The input domain is still continuous, and divided into slices based on a set of threshold values.
The idea is the following:
You create a d3.scaleThreshold to map any date (= continuous domain) to the fixed set of valid dates given your data by mapping it to the closest date. For that you have to specify the domain as an array of n - 1 dates which are residing in between the n valid dates. The range is the array of the valid dates.
It might not be as efficient as d3.bisect depending on your data.
const data_original = [{ date: "2021-03-18", value: "38.10"},
{ date: "2021-03-19", value: "38.60"},
{ date: "2021-03-22", value: "38.80"},
];
const data_types_converted = data_original.map(d => ({"date": new Date(d.date), "value": +d.value}));
const data_just_dates = data_types_converted.map(d => d.date);
let newDate = new Date("2021-03-17");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-18");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-19");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-20");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-21");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-22");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-23");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
function getClosestDate(newDate, validDates) {
const domain = [];
let midday_local;
let midday_UTC;
validDates.forEach((d,i) => {
if (i < validDates.length - 1) {
midday_local = new Date((validDates[i].getTime() + validDates[i + 1].getTime()) / 2); // midday in local time
midday_UTC = convertDateToUTC(midday_local); // midday in UTC time
domain.push(midday_UTC);
}
});
const scale = d3.scaleThreshold()
.domain(domain)
.range(validDates);
return scale(newDate)
}
function convertDateToUTC(date) {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
);
}
<script src="https://d3js.org/d3.v6.min.js"></script>
After hours spent to identify a rational or a solution, my hope is now with this community !
I'm desesperatly trying to get ("read") a time entered by user in a google spreasheet and to use it correctly in a google apps script for example to create google calendar event.
The desired format is "HH:mm"
My starting point is the google apps script example provided on https://developers.google.com/apps-script/quickstart/forms
From this example I modified the parameters of the spreasheet (sorry for the french!) using the "Change locale and time zone" instructions :
settings illustration
I also changed the display format of the columns 'C' and 'D' to not have the AM/PM put in the initial example:
Start Time End Time
13:00:00 14:55:00
13:00:00 14:55:00
...
To enable debug in script editor, I removed "_" at the end of setUpConference (line 14).
I launched the script "setUpConference" in debug to check the values read from the datasheet.
My surprise is to have for the first data line
Ethics for monsters 5/15/2013 13:00:00 14:55:00 Rm 323: Minotaur's Labyrinth
the corresponding data of the variable "session"
["Ethics for monsters", (new Date(1368568800000)), (new Date(-2209115361000)), (new Date(-2209108461000)), "Rm 323: Minotaur's Labyrinth"]
and sessions[2] is showned in the script editor as:
Sat Dec 30 1899 13:50:39 GMT+0100 (CET)
I understand that having only "time" (HH:mm), the date is incomplete (so the 1899 day) but how to obtain the time "13:00:00" rather than this strange "13:50:39" ?
Ps: my calendar time zone is also GMT+0100 (CET)
some edits with more information:
I share the google spreadsheet I used for test
I simplified the code of my google app script to focus on the issue (initial code was the one provided by google on https://developers.google.com/apps-script/quickstart/forms
/**
* A special function that inserts a custom menu when the spreadsheet opens.
*/
function onOpen() {
var menu = [{name: 'Set up conference', functionName: 'setUpConference'}];
SpreadsheetApp.getActive().addMenu('Conference', menu);
}
/**
* A set-up function that uses the conference data in the spreadsheet to create
* Google Calendar events, a Google Form, and a trigger that allows the script
* to react to form responses.
*/
function setUpConference() {
/* if (ScriptProperties.getProperty('calId')) {
Browser.msgBox('Your conference is already set up. Look in Google Drive!');
}*/
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Conference Setup');
var range = sheet.getDataRange();
var values = range.getValues();
setUpCalendar(values, range);
}
/**
* Creates a Google Calendar with events for each conference session in the
* spreadsheet, then writes the event IDs to the spreadsheet for future use.
*
* #param {String[][]} values Cell values for the spreadsheet range.
* #param {Range} range A spreadsheet range that contains conference data.
*/
function setUpCalendar(values, range) {
// comment cal for debug
//var cal = CalendarApp.createCalendar('Test Conference Calendar');
for (var i = 1; i < values.length; i++) {
var session = values[i];
var title = session[0];
Logger.log("i= "+i+" - "+ "session[2]= " + session[2] + " | session[3] =" + session[3] );
// This formats the date as Greenwich Mean Time in the format
// year-month-dateThour-minute-second.
var formattedHour = Utilities.formatDate(session[2], "GMT+1", "HH:mm");
Logger.log("formattedHour = "+formattedHour);
var start = joinDateAndTime(session[1], session[2]);
var end = joinDateAndTime(session[1], session[3]);
var options = {location: session[4], sendInvites: true};
// comment cal and event creation
/*var event = cal.createEvent(title, start, end, options)
.setGuestsCanSeeGuests(false);
session[5] = event.getId();*/
}
range.setValues(values);
}
/**
* Creates a single Date object from separate date and time cells.
*
* #param {Date} date A Date object from which to extract the date.
* #param {Date} time A Date object from which to extract the time.
* #return {Date} A Date object representing the combined date and time.
*/
function joinDateAndTime(date, time) {
date = new Date(date);
date.setHours(time.getHours());
date.setMinutes(time.getMinutes());
return date;
}
As linked in some of the comments sheets and JS use different date epochs and they don't always play nice.
change the var values = range.getValues(); to var values = range.getDisplayValues();
this will force it to grab the cells values as string.
changing your date join function as follows will make it handle the strings(may need to ensure the dates in your spread sheet to have leading zeros):
function joinDateAndTime(date, time) {
var t = new Date(date);
t.setHours(parseInt(time.substring(0, 2)));
t.setMinutes(parseInt(time.substring(3, 5)));
return t;
}
I am new to the dc.js library and wanted to do the crossfilter calculation below on group method of my geochoropleth chart. I am pretty sure there is some function I could pass to the reduce method of group.
I have the following data in DATA.csv (the first row contains column names):
BUDGET,GID,MDIS,USPRO,TYPE,FILEURL,RVID,VERDATE,VERSTAT,SCORE
10428,ALI-G-006,Aliabad,Kunduz,Hard,/uploadedfiles/reports/SIKA North/136-SIKA-North-ALI-G-006.pdf,0,19-08-2014,2,0
24853,ALI-G-008,Aliabad,Kunduz,Hard,/uploadedfiles/reports/SIKA North/561-SIKA-North-ALI-G-008.pdf,0,19-08-2014,0
24831,ALI-G-019,Aliabad,Kunduz,Hard,/uploadedfiles/reports/SIKA North/987-SIKA-North-ALI-G-019.pdf,0,18-08-2014,2,0
24771,IMA-G-017,Imam Sahib,Kunduz,Hard,/uploadedfiles/reports/SIKA North/557-SIKA-North- IMA-G-017.pdf,0,28-08-2014,2,1
21818,IMA-G-019,Imam Sahib,Kunduz,Hard,/uploadedfiles/reports/SIKA North/992-SIKA-North-IMA-G-019.pdf,0,27-08-2014,2,0
12266,KHA-G-007,Khanabad,Kunduz,Hard,/uploadedfiles/reports/SIKA North/583-SIKA-North - KHA-G-007.pdf,0,7/9/2014,1,0
23148,KUN-G-002,Kunduz,Kunduz,Hard,/uploadedfiles/reports/SIKA North/909-SIKA-North - KUN-G-002.pdf,0,1/9/2014,2,0
54584,KUN-G-004,Kunduz,Kunduz,Hard,/uploadedfiles/reports/SIKA North/702-SIKA-North - KUN-G-004 20140709.pdf,0,9/7/2014,1,0
24544,PUL-G-001,Pul-e Khumri,Baghlan,Hard,/uploadedfiles/reports/SIKA North/599-SIKA-North - PUL-G-001 - 20140623.pdf,0,6/7/2014,2,1
40149,SSKDAG046,Arghandab (1),Kandahar,Hard,/uploadedfiles/reports/SIKA South/239-SIKA-South-SSKDAG046.pdf,0,12/9/2014,0,0.625
39452,0003 LGR MAG,Muhammad Aghah,Logar,Hard,/uploadedfiles/reports/SIKA East/792-SIKA-East - 0003 LGR MAG - 20140610.pdf,0,10/6/2014,2,0.7
58298,0013 LGR MAG,Muhammad Aghah,Logar,Hard,/uploadedfiles/reports/SIKA East/591-SIKA-East - 0013 LGR MAG 20140601.pdf,0,1/6/2014,2,0]
Below is the dimension and group for my chart:
var facts = crossfilter(data);
var scoref = facts.dimension(function (d) { return d.district;});
var scoreg = scoref.group().reduceSum(function(d){return d.score;});
The d.score field's value is calculated using the code below with PHP:
$tempsql = $dbase->query('select "VERMDIS", COUNT(*) AS TOTAL, SUM("VERSTAT") AS SAM FROM mt_fver GROUP BY "VERMDIS"');
while ($r = pg_fetch_array($tempsql)) {
$dist = $r['VERMDIS'];
$score = $r[2] / (2 * $r[1]);
$disxx[$dist] = $score;
}
What I would like to achieve is to do the same calculation using group().reduce(function (p,v) { /* ... */ }) from the dc.js library while grouping the values by district names.
What results/errors are you getting? Looks like pretty much the right idea, but take into account:
if you're using d3.csv(), it will return the values as strings, so you'll need either to preprocess your data, or use +d.score to convert the values while reading them
the field may come out as d.SCORE depending how you are reading the CSV in.
you may need to adapt the reduce function to suit your calculation
If you put a line break in the function you pass to reduce, you can set a breakpoint there using the browser's debugger and experiment on the console to figure out what expression works for what you need.
It's ok when I run the example-6-llda-learn.scala as follows:
val source = CSVFile("pubmed-oa-subset.csv") ~> IDColumn(1);
val tokenizer = {
SimpleEnglishTokenizer() ~> // tokenize on space and punctuation
CaseFolder() ~> // lowercase everything
WordsAndNumbersOnlyFilter() ~> // ignore non-words and non-numbers
MinimumLengthFilter(3) // take terms with >=3 characters
}
val text = {
source ~> // read from the source file
Column(4) ~> // select column containing text
TokenizeWith(tokenizer) ~> // tokenize with tokenizer above
TermCounter() ~> // collect counts (needed below)
TermMinimumDocumentCountFilter(4) ~> // filter terms in <4 docs
TermDynamicStopListFilter(30) ~> // filter out 30 most common terms
DocumentMinimumLengthFilter(5) // take only docs with >=5 terms
}
// define fields from the dataset we are going to slice against
val labels = {
source ~> // read from the source file
Column(2) ~> // take column two, the year
TokenizeWith(WhitespaceTokenizer()) ~> // turns label field into an array
TermCounter() ~> // collect label counts
TermMinimumDocumentCountFilter(10) // filter labels in < 10 docs
}
val dataset = LabeledLDADataset(text, labels);
// define the model parameters
val modelParams = LabeledLDAModelParams(dataset);
// Name of the output model folder to generate
val modelPath = file("llda-cvb0-"+dataset.signature+"-"+modelParams.signature);
// Trains the model, writing to the given output path
TrainCVB0LabeledLDA(modelParams, dataset, output = modelPath, maxIterations = 1000);
// or could use TrainGibbsLabeledLDA(modelParams, dataset, output = modelPath, maxIterations = 1500);
But it's not ok when I change the last line from:
TrainCVB0LabeledLDA(modelParams, dataset, output = modelPath, maxIterations = 1000);
to:
TrainGibbsLabeledLDA(modelParams, dataset, output = modelPath, maxIterations = 1500);
And the method of CVB0 cost much memory.I train a corpus of 10,000 documents with about 10 labels each document,it will cost 30G memory.
I've encountered the same situation and indeed I believe it's a bug. Check GIbbsLabeledLDA.scala in edu.stanford.nlp.tmt.model.llda under the src/main/scala folder, from line 204:
val z = doc.labels(zI);
val pZ = (doc.theta(z)+topicSmoothing(z)) *
(countTopicTerm(z)(term)+termSmooth) /
(countTopic(z)+termSmoothDenom);
doc.labels is self-explanatory, and doc.theta records the distribution (counts, actually) of its labels, which has the same size as doc.labels.
zI is index variable iterating doc.labels, while the value z gets the actual label number. Here comes the problem: it's possible this documents has only one label - say 1000 - therefore zI is 0 and z is 1000, then doc.theta(z) gets out of range.
I suppose the solution would be to modify doc.theta(z) to doc.theta(zI).
(I'm trying to check whether the results would be meaningful, anyway this bug has made me not so confident in this toolbox.)