Can D3.js visualizations be served using Hugo? - html

I have some D3.js visualizations I want to server on a Github Pages website I made using Hugo. I'm struggling how to include the visualization (html and js file) within the markdown file. Is this possible? If not, can I just use a standalone html file on Hugo?
Edit:
I implemented the example #timur suggested but the plot still doesn't show.

It's doable, as long as you can include javascript files for D3 itself and your chart definition:
Consider a slightly cut down version of this example:
/static/example.js
margin = ({top: 20, right: 0, bottom: 30, left: 40})
height = 500
width = 500
data = [
{name: "E", value: 0.12702},
{name: "T", value: 0.09056},
{name: "A", value: 0.08167},
{name: "O", value: 0.07507},
{name: "I", value: 0.06966},
{name: "N", value: 0.06749},
{name: "S", value: 0.06327},
{name: "H", value: 0.06094},
{name: "R", value: 0.05987},
{name: "D", value: 0.04253},
{name: "L", value: 0.04025},
{name: "C", value: 0.02782},
{name: "U", value: 0.02758},
{name: "M", value: 0.02406},
{name: "W", value: 0.0236},
{name: "F", value: 0.02288},
{name: "G", value: 0.02015},
{name: "Y", value: 0.01974},
{name: "P", value: 0.01929},
{name: "B", value: 0.01492}
]
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0))
y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - margin.bottom, margin.top])
x = d3.scaleBand()
.domain(data.map(d => d.name))
.range([margin.left, width - margin.right])
.padding(0.1)
function zoom(svg) {
const extent = [[margin.left, margin.top], [width - margin.right, height - margin.top]];
svg.call(d3.zoom()
.scaleExtent([1, 8])
.translateExtent(extent)
.extent(extent)
.on("zoom", zoomed));
function zoomed() {
x.range([margin.left, width - margin.right].map(d => d3.event.transform.applyX(d)));
svg.selectAll(".bars rect").attr("x", d => x(d.name)).attr("width", x.bandwidth());
svg.selectAll(".x-axis").call(xAxis);
}
}
const svg = d3.select(".visualisation")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
svg.append("g")
.attr("class", "bars")
.attr("fill", "steelblue")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", d => x(d.name))
.attr("y", d => y(d.value))
.attr("height", d => y(0) - y(d.value))
.attr("width", x.bandwidth());
svg.append("g")
.attr("class", "x-axis")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis")
.call(yAxis);
content/posts/my-first-post.md
---
title: "D3.js bars"
date: 2020-03-24T00:00:00Z
draft: false
---
### Hello
<div class="visualisation"> </div> <!-- Hugo supports html in markdown -->
<script src = "https://cdnjs.cloudflare.com/ajax/libs/d3/5.15.0/d3.js"></script> <!-- load d3.js from CDN. you could potentially load it from /static folder as well-->
<script src = "/example.js"></script> <!-- this will pick our scipt up and render the chart -->
This structure might not be ideal as you could probably stick javascript references into reusable layout of some sort and potentially parametrise the chart definition so you didn't have to repeat it for every page. Without knowing your specifics it's however a bit hard to make these suggestions. I'm just hoping it gives you a good enough hint to keep going.
UPD I'm pretty sure the code itself is working: see this jsfiddle. Hugo has different file layout, but point I'm trying to make here is it should all be a matter of ensuring both your javascript files get loaded.
UPD2 starting version 0.60.0 Hugo will not by default allow unsafe html content (such as tags). To get it to work you need to enable it:
markup:
goldmark:
renderer:
unsafe: true

Related

Chart.js graphs rendered incorrectly on Chrome and Edge

Something I just noticed, is that graphs in Chart.js are rendered with double X and Y axes on Chrome and Edge. They are looking as I want them on Firefox. I'm sure they were ok on Chrome a few weeks ago.
Is this a bug in Graph.js or do I have my code wrong?
This is how it looks in Firefox:
And this is in Edge and Chrome:
There is a second Y axis ranging from 0 to 1, and the X axis has the days in what looks like Unix time and a secondary axis with times per 4 hours.
The website is http://www.maasluip.nl/energyprice/SPOT.html
The script for the first graph is this:
var ctx = document.getElementById('SpotWeek');
var PVDay = new Chart(ctx, {
type: 'line',
data: {
labels: [
'2022-11-12 00:00:00','2022-11-12 01:00:00','2022-11-12 02:00:00','2022-11-12 03:00:00','2022-11-12 04:00:00','2022-11-12 05:00:00','2022-11-12 06:00:00','2022-11-12 07:00:00','2022-11-12 08:00:00','2022-11-12 09:00:00','2022-11-12 10:00:00','2022-11-12 11:00:00','2022-11-12 12:00:00','2022-11-12 13:00:00','2022-11-12 14:00:00','2022-11-12 15:00:00','2022-11-12 16:00:00','2022-11-12 17:00:00','2022-11-12 18:00:00','2022-11-12 19:00:00','2022-11-12 20:00:00','2022-11-12 21:00:00','2022-11-12 22:00:00','2022-11-12 23:00:00','2022-11-13 00:00:00','2022-11-13 01:00:00','2022-11-13 02:00:00','2022-11-13 03:00:00','2022-11-13 04:00:00','2022-11-13 05:00:00','2022-11-13 06:00:00','2022-11-13 07:00:00','2022-11-13 08:00:00','2022-11-13 09:00:00','2022-11-13 10:00:00','2022-11-13 11:00:00','2022-11-13 12:00:00','2022-11-13 13:00:00','2022-11-13 14:00:00','2022-11-13 15:00:00','2022-11-13 16:00:00','2022-11-13 17:00:00','2022-11-13 18:00:00','2022-11-13 19:00:00','2022-11-13 20:00:00','2022-11-13 21:00:00','2022-11-13 22:00:00','2022-11-13 23:00:00','2022-11-14 00:00:00','2022-11-14 01:00:00','2022-11-14 02:00:00','2022-11-14 03:00:00','2022-11-14 04:00:00','2022-11-14 05:00:00','2022-11-14 06:00:00','2022-11-14 07:00:00','2022-11-14 08:00:00','2022-11-14 09:00:00','2022-11-14 10:00:00','2022-11-14 11:00:00','2022-11-14 12:00:00','2022-11-14 13:00:00','2022-11-14 14:00:00','2022-11-14 15:00:00','2022-11-14 16:00:00','2022-11-14 17:00:00','2022-11-14 18:00:00','2022-11-14 19:00:00','2022-11-14 20:00:00','2022-11-14 21:00:00','2022-11-14 22:00:00','2022-11-14 23:00:00','2022-11-15 00:00:00','2022-11-15 01:00:00','2022-11-15 02:00:00','2022-11-15 03:00:00','2022-11-15 04:00:00','2022-11-15 05:00:00','2022-11-15 06:00:00','2022-11-15 07:00:00','2022-11-15 08:00:00','2022-11-15 09:00:00','2022-11-15 10:00:00','2022-11-15 11:00:00','2022-11-15 12:00:00','2022-11-15 13:00:00','2022-11-15 14:00:00','2022-11-15 15:00:00','2022-11-15 16:00:00','2022-11-15 17:00:00','2022-11-15 18:00:00','2022-11-15 19:00:00','2022-11-15 20:00:00','2022-11-15 21:00:00','2022-11-15 22:00:00','2022-11-15 23:00:00','2022-11-16 00:00:00','2022-11-16 01:00:00','2022-11-16 02:00:00','2022-11-16 03:00:00',
'2022-11-16 04:00:00','2022-11-16 05:00:00','2022-11-16 06:00:00','2022-11-16 07:00:00','2022-11-16 08:00:00','2022-11-16 09:00:00','2022-11-16 10:00:00','2022-11-16 11:00:00','2022-11-16 12:00:00','2022-11-16 13:00:00','2022-11-16 14:00:00','2022-11-16 15:00:00','2022-11-16 16:00:00','2022-11-16 17:00:00','2022-11-16 18:00:00','2022-11-16 19:00:00','2022-11-16 20:00:00','2022-11-16 21:00:00','2022-11-16 22:00:00','2022-11-16 23:00:00','2022-11-17 00:00:00','2022-11-17 01:00:00','2022-11-17 02:00:00','2022-11-17 03:00:00','2022-11-17 04:00:00','2022-11-17 05:00:00','2022-11-17 06:00:00','2022-11-17 07:00:00','2022-11-17 08:00:00','2022-11-17 09:00:00','2022-11-17 10:00:00','2022-11-17 11:00:00','2022-11-17 12:00:00','2022-11-17 13:00:00','2022-11-17 14:00:00','2022-11-17 15:00:00','2022-11-17 16:00:00','2022-11-17 17:00:00','2022-11-17 18:00:00','2022-11-17 19:00:00','2022-11-17 20:00:00','2022-11-17 21:00:00','2022-11-17 22:00:00','2022-11-17 23:00:00'],
datasets: [{
label: 'SPOT prijs ex BTW',
data: [
'0.13780','0.13421','0.13001','0.12680','0.12944','0.12968','0.15800','0.17250','0.17410','0.16693','0.14185','0.13030','0.13378','0.13782','0.14988','0.20001','0.18990','0.24070','0.23800','0.19971','0.17807','0.16760','0.16127','0.15870','0.16880','0.15221','0.14300','0.12700','0.13407','0.13529','0.13529','0.15075','0.15596','0.13157','0.12031','0.13300','0.13013','0.12500','0.13746','0.14145','0.14913','0.19890','0.19797','0.17310','0.15872','0.15000','0.14200','0.13300','0.10454','0.10411','0.11910','0.10800','0.11955','0.11999','0.16720','0.21661','0.22470','0.19257','0.17470','0.16812','0.15866','0.17510','0.20732','0.21285','0.21315','0.25418','0.27039','0.19794','0.17530','0.16800','0.15791','0.15000','0.13565','0.12818','0.12899','0.10828','0.10863','0.12594','0.16405','0.21193','0.22140','0.21000','0.20010','0.19868','0.18983','0.20565','0.22216','0.22299','0.21735','0.22167','0.21501','0.21493','0.17498','0.15000','0.13876','0.13600','0.10180','0.10040','0.14255','0.09686','0.07959','0.09110','0.12074','0.22990','0.28794','0.21540','0.17442','0.16378','0.16682','0.17400','0.20107','0.22058','0.23610','0.27746','0.26486','0.20207','0.15420','0.11410','0.09948','0.06491','0.05116','0.02777','0.01633','0.00510','0.00588','0.01106','0.09491','0.18000','0.22300','0.26180','0.20550','0.17990','0.17050','0.16500','0.18000','0.17950','0.17990','0.29473','0.30000','0.23200','0.19500','0.14684','0.15150','0.13242'],
backgroundColor: ['rgba(54, 162, 235, 1)'],
borderColor: ['rgba(54, 162, 235, 1)'],
borderWidth: 1,
pointRadius: 1,
},{
label: 'Consumentenprijs',
data: [
'0.24816','0.24382','0.23873','0.23485','0.23804','0.23833','0.27260','0.29015','0.29208','0.28341','0.25306','0.23908','0.24329','0.24818','0.26278','0.32343','0.31120','0.37267','0.36940','0.32307','0.29689','0.28422','0.27656','0.27345','0.28567','0.26560','0.25445','0.23509','0.24365','0.24512','0.24512','0.26383','0.27013','0.24062','0.22700','0.24235','0.23888','0.23267','0.24775','0.25258','0.26187','0.32209','0.32096','0.29087','0.27347','0.26292','0.25324','0.24235','0.20791','0.20739','0.22553','0.21210','0.22608','0.22661','0.28373','0.34352','0.35331','0.31443','0.29281','0.28485','0.27340','0.29329','0.33228','0.33897','0.33933','0.38898','0.40859','0.32093','0.29353','0.28470','0.27249','0.26292','0.24556','0.23652','0.23750','0.21244','0.21286','0.23381','0.27992','0.33786','0.34931','0.33552','0.32354','0.32182','0.31112','0.33026','0.35023','0.35124','0.34441','0.34964','0.34158','0.34149','0.29315','0.26292','0.24932','0.24598','0.20460','0.20290','0.25391','0.19862','0.17772','0.19165','0.22752','0.35960','0.42983','0.34205','0.29247','0.27959','0.28327','0.29196','0.32472','0.34832','0.36710','0.41715','0.40190','0.32593','0.26800','0.21948','0.20179','0.15996','0.14332','0.11502','0.10118','0.08759','0.08854','0.09480','0.19626','0.29922','0.35125','0.39820','0.33008','0.29910','0.28773','0.28107','0.29922','0.29862','0.29910','0.43804','0.44442','0.36214','0.31737','0.25910','0.26474','0.24165'],
backgroundColor: ['rgba(255, 73, 17, 1)'],
borderColor: ['rgba(255, 73, 17, 1)'],
borderWidth: 2,
pointRadius: 1,
}]
},
options: {
animation: false,
scales: {
yAxis: {
position: 'left',
beginAtZero: true,
title: {
text: 'Euro',
display: true
},
},
xAxis: {
type: 'time',
ticks: {
align: "center",
source: "data",
callback: function(value, index, values) {
return ((index % 24) == 0) ? value : null;}
},
offset: false,
padding: 1,
time: {
tooltipFormat: 'DD-MM-YYYY HH:mm',
displayFormats: {
hour: 'DD MMM'
}
}
}
}
}
});
I found out one thing: I have my x- and y-axis named xAxis and yAxis, and apparently that does not work anymore. Renaming them to x and y did fix a lot of errors but I still have some graphs that behave differently. Maybe they changed the logic of their processing, I don't know. Can't find anything about that.

Export Nested SCSS Map to Json

I am attempting to export my scss to JSON npm package sass-export
I can successfully export variables and maps one level deep, but the problem is I have a colour map(shown is just the first portion there are many colours in it) that is two levels deep. The error that is thrown is about unclosed parenthesis. Everything appears good to me, I have followed the docs to export maps but I can't find much more info on the subject. Thanks for any insight you can provide.
Successfully exported
$z-index: (
"below-base": -1,
"base":0,
"xs": 100,
"sm": 200,
"md": 300,
"lg": 400,
"xl": 500
);
Console Output
mapValue:Array(7)
0: {name: "below-base", value: "-1", compiledValue: "-1"}
1: {name: "base", value: "0", compiledValue: "0"}
2: {name: "xs", value: "100", compiledValue: "100"}
3: {name: "sm", value: "200", compiledValue: "200"}
4: {name: "md", value: "300", compiledValue: "300"}
5: {name: "lg", value: "400", compiledValue: "400"}
6: {name: "xl", value: "500", compiledValue: "500"}
Unsuccessful
$colour-palette: (
gray: (
0: #0D0D0D,
1: #1A1A1A,
2: #262626,
3: #333333,
4: #5C5C5C,
5: #858585,
6: #ADADAD,
7: #D4D6DB
),
);
Terminal Error Output
{ Error: unclosed parenthesis
at Object.module.exports.renderSync (C:\Users\tbilcke\Documents\repos\node_modules\node-sass\lib\index.js:439:16)
status: 1,
file: 'stdin',
line: 193,
column: 34,
message: 'unclosed parenthesis',
formatted: 'Error: unclosed parenthesis\n on line 193 of stdin\n>> #sass-export-id.gray{content:"#{(0: #0D0D0D}";}\n ---------------------------------^\n' }
Console Output
colour-palette: Array(1)
0:
compiledValue:"(gray: (0: #0D0D0D, 1: #1A1A1A, 2: #262626, 3: #333333, 4: #5C5C5C, 5: #858585, 6: #ADADAD, 7: #D4D6DB))"
mapValue: Array(1)
0: {name: "gray", value: "(0: #0D0D0D", compiledValue: ""}
length:1
__proto__: Array(0)
name: "$colour-palette"
value :
"(gray: (0: #0D0D0D,1: #1A1A1A,2: #262626,3: $gray-base,4: #5C5C5C,5: #858585,6: #ADADAD,7: #D4D6DB),)"
Sass Export - Working
let __root = path.join(__dirname, '../')
let __src = path.join(__dirname, '../src')
let exportPath = path.join(__src, 'scss/_test_cars.scss')
let importPath = path.join(__src, 'scss/')
let options = {
inputFiles: [exportPath],
includePaths: [importPath]
}
let asObject = exporter(options).getStructured()
process.env.styles = JSON.stringify(asObject)
I recently encountered the same issue and managed to resolve it with a relatively painless workaround.
If you take your child arrays and separate them out like so;
$colour-palette-gray: (
0: #0D0D0D,
1: #1A1A1A,
2: #262626,
3: #333333,
4: #5C5C5C,
5: #858585,
6: #ADADAD,
7: #D4D6DB
);
and then in a separate scss file (which you dont observe with sass-export) load them into the parent array
$colour-palette: (
'grey': $colour-palette-gray,
'blue': $colour-palette-blue,
'pink': $colour-palette-pink
);
you can also use the special comment syntax above each child array declaration to ensure that the nodes in the JSON are labelled correctly;
/**
* #sass-export-section="brand-colors"
*/
I am using the gulp implementation of the module in this way and it works as desired

Plotting a function as a function of another function in Mathematica

I wasn't entirely sure what to search for, so if this question has been asked before, I apologize in advance:
I have two functions
R := Rref*mx(mx^(4/3) - C0)^(-1)
M := Mref*(mx + C1*mx^(-1)*((1 - C0*mx^(-4/3))^(-3) - 1))
where Rref, Mref, C0 and C1 are constants and mx is the variable. I need to plot R as a function of M. Surely there must be something available in Mathematica to do such a plot - I just can't seem to find it.
The comment is correct, in that what you have is a set of two "parametric equations". You would use the ParametricPlot command. However, the syntax of functions with parameters is sometimes tricky, so let me give you my best recommendation:
R[Rref_, C0_, C1_][mx_] = Rref*mx (mx^(4/3) - C0)^(-1);
M[Mref_, C0_, C1_][mx_] = Mref*(mx + C1*mx^(-1)*((1 - C0*mx^(-4/3))^(-3) - 1));
I like that notation better because you can do things like derivatives:
R[Rref,C0,C1]'[mx]
(* Output: -((4 mx^(4/3) Rref)/(3 (-C0 + mx^(4/3))^2)) + Rref/(-C0 + mx^(4/3)) *)
Then you just plot the functions parametrically:
ParametricPlot[
{R[0.6, 0.3, 0.25][mx], M[0.2, 0.3, 0.25][mx]},
{mx, -10, 10},
PlotRange -> {{-10, 10}, {-10, 10}}
]
You can box this up in a Manipulate command to play with the parameters:
Manipulate[
ParametricPlot[
{R[Rref, C0, C1][mx], M[Mref, C0, C1][mx]},
{mx, -mmax, mmax},
PlotRange -> {{-10, 10}, {-10, 10}}
],
{Rref, 0, 1},
{Mref, 0, 1},
{C0, 0, 1},
{C1, 0, 1},
{mmax, 1, 10}
]
That should do it, I think.

AngularJS: How to access scope from directive

I'm using a directive to draw graphs:
drawGraph.directive "graph", ->
restrict: "E" # Use as element
scope: # Isolate scope
data: "=" # Two-way bind data to local scope
opts: "=?" # '?' means optional
template: "<div></div><div id='{{graph.id}}'></div>" # We need a div to attach graph to
link: (scope, elem, attrs) ->
graph = new Dygraph(elem.children()[0], scope.data, scope.opts)
While
<div id='{{graph.id}}'>
actually works in the partial, it returns
<div id></div>
when I use it in the template of the directive. Can anyone tell me why?
Update:
After the hint of #Marek, my directive now looks like this:
drawGraph.directive "graph", ->
restrict: "E" # Use as element
scope: # Isolate scope
data: "=" # Two-way bind data to local scope
opts: "=?" # '?' means optional
template: "<div></div><div class='legend'></div>" # We need a div to attach graph to
link: (scope, elem, attrs) ->
scope.opts.labelsDiv = elem.children()[0].getElementsByClassName("legend")[0]
scope.graph = new Dygraph(elem.children()[0], scope.data, scope.opts)
Options are added in the controller:
drawGraph.controller "MyCtrl", [ "myService", "$scope", (myService, $scope) ->
myService.async().then (d) ->
rawData = d
group = rawData
i = 0
while i < group.length
j = 0
while j < group[i].data.length
# Convert date
tmp = new Date(group[i].data[j][0])
group[i].data[j][0] = tmp
# Set draw options
group[i].opts =
labels: [ "x", "Your Price", "Market Price" ],
customBars: true,
labelsSeparateLines: "true",
hideOverlayOnMouseOut: false,
legend: "always",
showRangeSelector: true,
xAxisLabelWidth: 80,
++j
++i
$scope.graphs = group
Problem was that an isolated scope can't access the parent scope by default, so "id" needs to be defined in the scope of the directive.
drawGraph.directive "graph", [(graph) ->
restrict: "E"
scope:
data: "="
opts: "=?"
id: "="
You're not actually putting the graph into the scope.
The last line should be:
scope.graph = new Dygraph(elem.children()[0], scope.data, scope.opts)

Excel header title from html code in Matlab

I have an uitable whose header's title (variable "header") uses html code. I want to export the uitable data (included its header) to an Excel spreadsheet. This is the code written for this task:
%# header = get(htable,'ColumnName');
header = {'<html><center>Component X<br />(km/s<sup>2</sup>)</center></html>', ...
'<html><center>Component Y<br />(km/s<sup>2</sup>)</center></html>', ...
'<html><center>Component Z<br />(km/s<sup>2</sup>)</center></html>'},
numeric_data = rand(3,3);
data_Matrix = [header ; num2cell(numeric_data)],
xlswrite('file.xls',data_Matrix);
However, I can not get Excel spreadsheet header title appears written correctly.
You can't insert HTML into an Excel cell like that (well you can, but as you've discovered it won't be rendered, it will just display the HTML).
In your specific case, you can make use of a little Unicode instead of HTML to display your titles both in the uitable and in Excel. Note that 00B2 is Unicode for superscript 2 - See Wikipedia for a list of other characters.
>> numeric_data = rand(3,3);
>> header2 = {['Component X (km/s',char(hex2dec('00B2')),')'],...
['Component Y (km/s',char(hex2dec('00B2')),')'],...
['Component Z (km/s',char(hex2dec('00B2')),')']}
header2 =
'Component X (km/s²)' 'Component Y (km/s²)' 'Component Z (km/s²)'
>> htable2 = uitable('ColumnName',header2);
>> data_Matrix = [header2 ; num2cell(numeric_data)]
data_Matrix =
'Component X (km/s²)' 'Component Y (km/s²)' 'Component Z (km/s²)'
[ 0.50095] [ 0.28778] [ 0.88857]
[ 0.33155] [ 0.50127] [ 0.62051]
[ 0.243] [ 0.89398] [ 0.6544]
>> xlswrite('file.xls',data_Matrix);