Question: Is there an automatic way to add the line numbers of the original R Markdown source code to the formatted code portions of the HTML output produced by knitr?
Purpose: My ultimate goal is to be able to quickly move to parts of my source R Markdown code that I identify need editing while reviewing the HTML output. Using line numbers is the fastest way I know to do this, but I welcome hearing others' strategies.
Solutions I've tried:
Although the chunk option attr.source = '.numberLines' will attractively add line numbers to the code parts of the HTML output, that option doesn't provide the source-code line numbers automatically (you must force that manually using .startFrom) -- instead, the lines are renumbered at the beginning of each chunk and after each piece of output. In the following illustration, I've included .startFrom to force the line numbering to start at 10, to match the line number for test_data <- rnorm(10) which is the line number I want to see. A practical solution, however, needs the starting number to be automatic. Also, in the HTML output (shown beneath the code) the hist(test_data) line is renumbered starting with the same starting number, 10. I would want that to be 12, as in the source code.
This question (How can I add line numbers that go across chunks in Rmarkdown?) is related, but the OP just needed any unique identifier for each line, not necessarily the line numbers of the source code, with the solution being sequential numbers unrelated to the source-code line numbers.
Considered option: I've considered preprocessing my code by running an initial script that will add line numbers as comments at the end of lines, but I'd prefer a solution that is contained within the main knitr file.
Reverted to this update based on your request
I'm glad you figured out the issue. I hadn't considered or tested the code for a chunk that only had a single line of code. However, based on your feedback, I've accounted for it now.
If you'd like it accounted for and would like to keep the color in the code, let me know. I'll add it back with the fix for single lines of code. (I'll stick to the ES6.)
This version uses the line numbers you'll see in the source pane of RStudio. You must use RStudio for this to work. The following changes to the RMD are necessary:
The library(jsonlite) and library(dplyr)
An R chunk, which you could mark include and echo as false
A set of script tags outside of and after that chunk
A JS chunk (modified from my original answer)
The R chunk and R script need to be placed at the end of your RMD.
The JS chunk can be placed anywhere.
The R chunk and script tags **in order!
Put me at the end of the RMD.
```{r ignoreMe,include=F,echo=F}
# get all lines of RMD into object for numbering; R => JS object
cx <- rstudioapi::getSourceEditorContext()$contents
cxt <- data.frame(rws = cx, id = 1:length(cx)) %>% toJSON()
```
<script id='dat'>`r cxt`</script>
The JS chunk
This collects the R object that you made in the R chunk, but its placement does not matter. All of the R code will execute before this regardless of where you place it in your RMD.
```{r gimme,engine="js",results="as-is",echo=F}
setTimeout(function(){
scrCx = document.querySelector("#dat"); // call R created JSON*
cxt = JSON.parse(scrCx.innerHTML);
echoes = document.querySelectorAll('pre > code'); // capture echoes to #
j = 0;
for(i=0; i < echoes.length; i++){ // for each chunk
txt = echoes[i].innerText;
ix = finder(txt, cxt, j); // call finder, which calls looker
stxt = txt.replace(/^/gm, () => `${ix++} `); // for each line
echoes[i].innerText = stxt; // replace with numbered lines
j = ix; // all indices should be bigger than previous numbering
}
}, 300);
function looker(str) { //get the first string in chunk echo
k = 0;
if(str.includes("\n")) {
ind = str.indexOf("\n");
} else {
ind = str.length + 1;
}
sret = str.substring(0, ind);
oind = ind; // start where left off
while(sret === null || sret === "" || sret === " "){
nInd = str.indexOf("\n", oind + 1); // loop if string is blank!
sret = str.substring(oind + 1, nInd);
k++;
ind = oind;
oind = nInd;
}
return {sret, k}; // return string AND how many rows were blank/offset
}
function finder(txt, jstr, j) {
txsp = looker(txt);
xi = jstr.findIndex(function(item, j){ // search JSON match
return item.rws === txsp.sret; // search after last index
})
xx = xi - txsp.k + 1; // minus # of blank lines; add 1 (JS starts at 0)
return xx;
}
```
If you wanted to validate the line numbers, you can use the object cx, like cx[102] should match the 102 in the HTML and the 102 in the source pane.
I've added comments so that you're able to understand the purpose of the code. However, if something's not clear, let me know.
ORIGINAL
What I think you're looking for is a line number for each line of the echoes, not necessarily anything else. If that's the case, add this to your RMD. If there are any chunks that you don't want to be numbered, add the chunk option include=F. The code still runs, but it won't show the content in the output. You may want to add that chunk option to this JS chunk.
```{r gimme,engine="js",results="as-is"}
setTimeout(function(){
// number all lines that reflect echoes
echoes = document.querySelectorAll('pre > code');
j = 1;
for(i=0; i < echoes.length; i++){ // for each chunk
txt = echoes[i].innerText.replace(/^/gm, () => `${j++} `); // for each line
echoes[i].innerText = txt; // replace with numbered lines
}
}, 300)
```
It doesn't matter where you put this (at the end, at the beginning). You won't get anything from this chunk if you try to run it inline. You have to knit for it to work.
I assembled some arbitrary code to number with this chunk.
Related
I am a "new" developer into the foray of Web Development and I have come across an issue I was hoping that you fine people on Stack Overflow would be able to help me with. I have asked several Cadre and Instructors in my class and we are all stumped by it.
To start with I have decided to put all of my code on a Gitlab repo so if you want to look at the whole thing (or if you want to add to it let me know): Link to Github Repo. I fiqured you guys don't want the whole thing posted as a wall of text and rather some snip-its of what in the file I specifically. But it is relitively small file
I am useing simple JavaScript as well as Node.Js to be able to build a working calculator in the back end that I can use as a template for any other project I will need to work on in the future. For now I am trying to just get it working by imputing things via the console.
I have made a way for what is imputed in Node and to an imputArray var I have set up and the Array goes something like this:
[(command), (num1), (num2), (num3), ...]
I set up a switch function that runs a block of code based on what command was given (add, subtract, divide, etc..). As well as separating the command from the number and putting them inside another array.
The part I need some help with is with getting the block of code to work for what I want it to do. I have got it set up to run rather easily on two numbers but I want it to handle as many numbers as I want to throw at it. I tried various forms of for loops as well as forEach loops and I cant seem to get it working.
case 'divide':
for (i = 1; i < numArray.length; i++) { // If any number besides the first is 0 spit out this
if (numArray[i] === 0) {
consol.log("You canot divide by zero!");
}
else {
var previousTotal = numArray[0]; //Inital number in array
for (i = 1; i < numArray.length; i++) {
previousTotal = previousTotal / numArray[i]; // for each number in array divide to the previous number
}
}
result = previousTotal // Pushes end total to result
}
break;
I have gone through several different versions of the above code (such as using for loops instead) but this is pretty much what I ended up with. I'm sure there is an easier way and more sane way to do what I am trying to do, but if I knew how I wouldn't be here.
Essentially this is the ideal thing I want to do but I cant find a way to do it: I want to run a small block of code the index of the number array, minus one. In this case it is dividing the previous number by the next number in the array.
So it only runs if there are more then one in the array and it does the function to the previous number, or total from the last one in the array.
This is pretty much the only thing holding me back from finishing this so if someone can take the time to look at my crapy code and help it do what I want it to do that would be awesome.
Your code is reseting result each time the outer loop iterates so it will just equal what ever the last prev Total is. Basically every loop but the last is irrelevant. Do you want to add them to result? If so you want:
result += previousTotal
Or if you want an array of the answers you want:
result.push(reviousTotal)
Sorry not 100% what you want. Hope this helps!
You just need one loop, and you probably want to stop iterating if a 0 occurs:
result = numArray[0]; //no need for another variable
for (var i = 1; i < numArray.length; i++) { // declare variables!
if (numArray[i] === 0) {
console.log("You canot divide by zero!"); // typo...
break; // exit early
}
result = result / numArray[i];
}
For sure that can be also written a bit more elegantly:
const result = numArray.reduce((a, b) => a / b);
if(isNaN(result)) {
console.log("Can't divide by zero!");
} else {
console.log(`Result is ${result}`);
}
I assume you want the divide command to do ((num1/num2)/num3)/...
There are couple of issues in the code you posted, I will post a version that does the above. You can inspect and compare it your version to find your mistakes.
// divide, 10, 2, 5
case 'divide':
if (numArray.length < 2) {
console.log("no numbers in array")
break;
}
// previousTotal starts with 10
var previousTotal = numArray[1];
// start from the second number which is 2
for (i = 2; i < numArray.length; i++) {
if (numArray[i] === 0) {
console.log("You canot divide by zero!");
}
else {
previousTotal = previousTotal / numArray[i]; // for each number in array divide to the previous number
}
}
result = previousTotal;
// result will be (10/2)/5 = 1
break;
I'm looking to write a small parser for some kind of files, and one of the things I have to accomplish is to find if a line is inside another one, defining this with indentation (spaces or tabs).
Example:
This is the main line
This is a nested or child line
I'm trying to establish this by reading the first character position in the line and comparing it with the previous one with something like this:
var str = ' hello';
str.indexOf(str.match(/\S|$/).shift());
I'm sure this is not the best way and it looks horrible, also I have another issues to address, like checking if the indentation is made by spaces (2 or 4), or tabs, or passing/maintaining an state of the previous line (object).
Also, lines can be infinitely nested and of course I'm looking more for a nice and performant algorithm (or idea), or pattern rather than a simple check that I think is relatively easy to do but error prone. I'm sure it is already solve by people who works with parsers and compilers.
Edit:
str.search(/\S/);
#Oriol proposal looks much better
This is generally the kind of thing you write a parser for, rather than purely relying on regex. If the nesting determines the depth, then you have two things to solve: 1) find the depth for an arbitrary line, and 2) iterate through the set of lines and track, for each line, which preceding line has a lower depth value.
The first is trivial if you are familiar with the RegExp functions in Javascript:
function getDepth(line) {
// find leading white space
var ws = str.match(/^(\s+)/);
// no leading white space?
if (ws === null) return 0;
// leading white space -> count the white space symbols.
// obviously this goes wrong for mixed spaces and tabs, and that's on you.
return ws[0].split('').length;
}
The second part is less trivial, and so you have several options. You could iterate through all the lines, and track the list of line numbers, pushing onto the list as you go deeper and popping from the list as you go back up, or you can build a simple tree structure (which is generally far better because it lets you expand its functionality much more easily) using standard tree building approached.
function buildTree(lines, depths) {
if (!depths) {
var depths = lines.map(e => getDepth);
return buildTree(lines, depths);
}
var root = new Node();
for(var pos=0, end=lines.length; pos<end; pos++) {
var line = lines[pos];
var depth = depths[pos];
root.insert(line, depth);
}
}
With a simple Node object, of course
var Node = function(text, depth) {
this.children = [];
this.line = text.replace(/^\s+/,'');
this.depth = depth;
}
Node.prototype = {
insert: function(text, depth) {
// this is where you become responsible: we need to insert
// a new node inside of this one if the depths indicate that
// is what should happen, but you're on the hook for determining
// what you want to have happen if the indentation was weird, like
// a line at depth 12 after a line at depth 2, or vice versa.
}
}
I'd like to use Seshat—a handwritten math expression parser—for a project I'm working on, but I'm having some trouble understanding how to provide the program its proper input, an InkML or SCG Ink file.
I've taken a long look at an online example that exists here, and I see that they get a Javascript array of stroke information from an HTML Canvas field with this JS library applied, but I don't know what happens that array after it gets POSTed to their server.
I've read the SCG Ink spec, and I think it might be relatively easy to parse the array into the format, but I'm hoping there's something obvious I'm missing that would make this trivial. Any help would be greatly appreciated.
I emailed the Seshat author and he suggested I convert the input to SCG Ink, which turned out to be pretty easy if you take the JavaScript libraries used at http://cat.prhlt.upv.es/mer/. Specifically, you want jquery.sketchable.memento.min.js, jquery.sketchable.min.js, and jsketch.min.js in addition to regular old jQuery. Here's what I did in case anyone else is interested in Seshat.
Notice from the same page that in main.js they apply the Sketchable library to the HTML canvas area with this block of code:
var $canvas = $('#drawing-canvas').sketchable({
graphics: {
strokeStyle: "red",
firstPointSize: 2
}
});
Now we can take a look at their submitStrokes() function to see how to take the strokes from Sketchable and convert to SCG Ink. The line var strokes = $canvas.sketchable('strokes'); gets the strokes, and then the line strokes = transform(strokes); applies a quick transformation to extract only the data they need. Here's the transform() function for reference:
function transform(strokes) {
for (var i = 0; i < strokes.length; ++i)
for (var j = 0, stroke = strokes[i]; j < stroke.length; ++j)
strokes[i][j] = [ strokes[i][j][0], strokes[i][j][1] ];
return strokes;
};
The value returned fro transform() is a three-dimensional array of strokes and points. (Each element of the first dimension is a stroke, each element of the second dimension is a point, and the third dimension is x-, y-coordinates.) On that site they go ahead and POST that array to the server which must handle the final conversion to SCG Ink. I wrote a JavaScript function to handle it:
function strokesToScg(strokes) {
var scg = 'SCG_INK\n' + strokes.length + '\n'
strokes.forEach(function (stroke) {
scg += stroke.length + '\n'
stroke.forEach(function (p) {
scg += p[0] + ' ' + p[1] + '\n'
})
})
return scg
}
And that's it. The value returned from strokesToScg() is a string describing a series of strokes in the SCG Ink format.
As far as I understand topojson.presimplify(JSON) in D3 adds Z coordinate to each point in the input topojson shape based on its significance, which then allows to use it for the dynamic simplification like in http://bl.ocks.org/mbostock/6245977
This method topojson.presimplify() takes quite a long time to execute on complicated maps, especially in Firefox which makes the browser unresponsive for few seconds.
Can it be baked directly into the topojson file via the command line as it is done with projections:
topojson --projection 'd3.geo.mercator().translate([0,0]).scale(1)' -o cartesian.topo.json spherical.topo.json
I found a workaround for this which is not completely as simple as I wanted but still achieves the same result.
After the topojson.presimplify(data) is called, data already holds the pre simplified geometry with added Z axis values.
Then I convert it to the JSON string and manually copy it to a new file with JSON.stringify(data)
Nevertheless these conversion to a JSON string has a problem with Infinity values which often occur for Z and with JSON.stringify method are converted to null. Also when there is a value for Z coordinate it is usually too precise and writing all decimal points takes too much space.
For that reason before converting data to a JSON string I trim the numbers:
// Simplifying the map
topojson.presimplify(data);
// Changing Infinity values to 0, limiting decimal points
var arcs = data.arcs;
for(var i1 = arcs.length; i1--;) {
var arc = arcs[i1];
for(var i2 = arc.length; i2--;) {
var v = arc[i2][2];
if(v === Infinity) arc[i2][2] = 0;
else {
arc[i2][2] = M.round(v * 1e9)/1e9;
}
}
}
This makes Infinity values to appear as exactly 0 and other values are trimmed to 9 decimal points which is enough for dynamic simplification to work properly.
Since such string is too long to easily print it for copying to the new json file it is much easier to store it in the localStorage of the browser:
localStorage.setItem(<object name>, JSON.stringify(data))
Then in Safari or Chrome open the developer console and in the tab Resources -> Local Storage -> <Website URL> the stored object can be found, copied and then pasted into a text editor.
Usually it is pasted as a <key> <value> pair, so one needs to remove from the beginning of the pasted string so that it starts from {.
Since Infinity values have been converted to 0, in the dynamic simplification function it should be taken into account so that points with Z = 0 are treated as Z = Infinity and are always plotted with any simplification area:
point: function(x, y, z) {
if (z===0 || z >= simplificationArea) {
this.stream.point(x, y);
}
}
I use syntaxhighlighter on my blog to format C++ code. Since last few days I am getting extra blank line after each line after each line of code. Please see this link for more info.
Following is the code I wrote there. I am not seeing any line break in that.
//Define MAX 1 less so that adding 1 doesn't make it 0
#define MAX 0xFFFFFFFE;
unsigned int jump(int *array, int n)
{
unsigned int *result = new unsigned int[n];
int i, j;
//Boundry conditions
if (n == 0 || array[0] == 0)
return MAX;
result[0] = 0; //no need to jump at first element
for (i = 1; i < n; i++)
{
result[i] = MAX; //Initialization of result[i]
for (j = 0; j < i; j++)
{
//check if jump is possible from j to is
if (array[j] >= (i-j))
{
//check if better solution available
if ((result[j] + 1) < result[i])
result[i] = result[j] + 1; //updating result[i]
}
}
}
//return result[n-1]
unsigned int answer = result[n-1];
delete[] result;
return answer;
}
Surprisingly this is happening only for new posts, all old posts are shown currently w/o extra blank lines.
Your source code (before JavaScript) basically looks like this:
<pre>
First line
<br />Another line
<br />Last line
</pre>
If you are using a <pre> tag, you don't need to insert <br /> tags to force line feeds but, if you do, they should replace the original line feed.
Update: I'll make a blind guess with the little information we have. Your code is saved into a local file using Windows line feeds (CR+LF). The server runs Linux and applies a function that replaces Linux line feeds (LF). with <br /> tags so you end up with CR<br />. This is inserted into a <pre> tag so the browser converts this to two consecutive line feeds.
My hypothesis seems likely because, if you save the HTML source code into a file and open it with a text editor that can display line feeds, it'll show the file is using Linux style (LF) everywhere expect in the code snippet, where it's using CR (old MacOS 9 style).
Workaround: save the file as Unix before copying or copy with another editor or copy to another browser.