Wowchemy-hugo-modules: Add data visualization feature

Created on 30 Apr 2020  Â·  27Comments  Â·  Source: wowchemy/wowchemy-hugo-modules

It might be a good idea to integrate chart.js to the theme as default and leave an option in the config file.
image
examples

enhancement

Most helpful comment

Plotly.js may be a better option to explore initially since a significant number of users are already using Plotly with Python/R for data analytics/science?

All 27 comments

+1 on this feature!!

Plotly.js may be a better option to explore initially since a significant number of users are already using Plotly with Python/R for data analytics/science?

I use plotly. It is easy to use, you should have a try.

@YonghuiDong I would like to try! Do you have tutorials that I could refer to?

@renegades12 You can check this website: https://plotly.com/graphing-libraries/.

@gcushen I also prefer PlotlyJs but there is currently an issue using MathJax v3 and plotlyjs: plotly cannot be loaded. The problem comes from plotlyjs.

See the issue

In a lot of my work I'm interested in GIS maps and data. I have looked at amCharts several times: https://www.amcharts.com/ it is not maybe the best fit for this project, but I'd hope that what ever plotting lib was chosen would also support GIS displays. I'm coming at this from a sans R position. I do not use any of the R tooling with Academic.

@HughP It seems to be a powerful library. It's a freeware (free of charge if we let an attribution). The source code is available but I do not think it is "open-source" (?) If so, this might be a no-go for certain users.

@gcushen I also prefer PlotlyJs but there is currently an issue using MathJax v3 and plotlyjs: plotly cannot be loaded. The problem comes from plotlyjs.

See the issue

I can't thank you enough for this. Spent hours trying to understand why Plotly wouldn't work with Hugo for me. Is there an alternative to MathJax v3 that could work with Plotly and Hugo? I also do prefer support to Plotly.

@lucasfr As far as I know: no. It's simply impossible to use PlotlyJS + Mathjax v3. The problem does not come from Hugo but from PlotlyJs. It checks if mathjax has been loaded, if that is the case, plotlyjs does some stuff about configuration of MathJax, which does not work with mathjax v3 (breaking changes from v2 to v3), leading to a crash of plotlyjs.

As I still use plotlyjs, I simply turn off Mathjax on the pages where I use plotlyjs (math = false). This is quite ugly, I know... :)

@Bertbk thank you. It worked for me too. However I am between a rock and a hard place as I need both some support to maths and plotly. Have even considering going back to MathJaxV2 but haven't been very successful, as I'm not very skilled with CSS and JS.

going back to MathJaxV2

That should be easy to do: In the page you want to use mathjax2, ...

  • set math=false
  • add these lines in the end of the .md file (in the body, with your markdown)
<script async src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_CHTML"></script>

You can also create a /layouts/partials/custom_js.html (you might need to create the folder, this is NOT in the /themes/academic folder!) file with this inside

<script async src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_CHTML"></script>

The problem is that you would need to set math=false everywhere. You can add a parameter, though, but I believe the first solution is the best: it does not affect the other pages and you can revert to MathJax3 easily.

@Bertbk Thank you for the suggestions. I have tried on both .md and .Rmd files without success. It keeps showing equations either between $ $ or \( \).

@lucasfr We should switch to the forum and we'll find a solution :)

I try to build a chart as a default theme using chartjs. I am using Academia Hugo to be my main theme. Also, There are 3 file added including a json, a theme html and a md.

In the markdown file, I have add a tag called "[chart]". User can thougth this tag to get the new theme. In addition, I create 2 choices to generate a chart. The first one is using JSON. the user just needs to put a json into the tag called "json", then the chart will be generated. The second one is using tag for insert or edit the chart detail. Details as follows:

chart.md

# A section created with the Chart widget.
widget = "chart"  # See https://sourcethemes.com/academic/docs/page-builder/
headless = true  # This file represents a page section.
active = true  # Activate this widget? true/false
weight = 22  # Order that this section will appear.

# Note: a full width section format can be enabled by commenting out the `title` and `subtitle` with a `#`.
title = "Chart"
subtitle = ""
[design]
  # Choose how many columns the section has. Valid values: 1 or 2.
  columns = "2"
  format = "2"  # Change the chart and text position. Valid values: 1 or 2.

[design.background]
  # Apply a background color, gradient, or image.
  #   Uncomment (by removing `#`) an option to apply it.
  #   Choose a light or dark text color by setting `text_color_light`.
  #   Any HTML color name or Hex value is valid.

  # Background color.
  # color = "navy"

  # Background gradient.
  # gradient_start = "DeepSkyBlue"
  # gradient_end = "SkyBlue"

  # Background image.
  # image = "image.jpg"  # Name of image in `static/img/`.
  # image_darken = 0.6  # Darken the image? Range 0-1 where 0 is transparent and 1 is opaque.

  # Text color (true=light or false=dark).
  # text_color_light = true

[design.spacing]
  # Customize the section spacing. Order is top, right, bottom, left.
  # padding = ["0px", "0px", "0px", "0px"]

[advanced]
 # Custom CSS. 
 css_style = ""

 # CSS class.
 css_class = ""

 [chart]
 #2 Style for generate chart

 #Using JSON to generate a chart
 json="../json/testData3.json"

 #Using tag to generate a chart
 id = "myChart"
 chart_label = "Source Rank"
 backgroundColor = "rgba(255,207,47,0.6)"
 borderColor = "rgba(255,207,47)"
 borderWidth = "2"
 yGridLines = "false"
 xGridLines = "false"
 type = ""
 data = "a:1,b:2,c:3,d:4,e:5"

+++

In the html file, If you want to using the the second choice, you need to uncomment the code first, and then comment the getjson part. Also, you need to put the html file to the theme file first.

chart.html

<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
{{ $st := .page }}
{{ $columns := $st.Params.design.columns | default "2" }}
{{ $format := $st.Params.design.format | default "1" }}
<div class="row">
  {{ if ne $columns "1" }}
    <div class="col-12 section-heading text-center">
      {{ with $st.Title }}<h1>{{ . | markdownify | emojify }}</h1>{{ end }}
      {{ with $st.Params.subtitle }}<p>{{ . | markdownify | emojify }}</p>{{ end }}   

    </div>

    {{ if eq $st.Content "" }}
        <div class="col-12">
            <!--<canvas id="{{ $st.Params.chart.id}}" width="600" height="400"></canvas>-->
            <div id="chartInfo" class="chartInfo"></div>

        </div>
    {{ else }}
        {{ if eq $format "1"  }}
            <div class="col-12 col-lg-6">
                <!--<canvas id="{{ $st.Params.chart.id}}" width="600" height="400"></canvas>-->
                <div id="chartInfo" class="chartInfo"></div>
            </div>
            <div class="col-12 col-lg-6">
                {{ $st.Content }}
            </div>
        {{ else }}
            <div class="col-12 col-lg-6">
                {{ $st.Content }}
            </div>
            <div class="col-12 col-lg-6">
                <!--<canvas id="{{ $st.Params.chart.id}}" width="600" height="400"></canvas>-->
                <div id="chartInfo" class="chartInfo"></div>
            </div>
        {{ end }}
    {{ end }}

  {{ else }}
    <div class="col-12">
      {{ with $st.Title }}<h1>{{ . | markdownify | emojify }}</h1>{{ end }}
      {{ with $st.Params.subtitle }}<p>{{ . | markdownify | emojify }}</p>{{ end }}
    </div>
    {{ if eq $st.Content "" }}
        <div class="col-12">
            <!--<canvas id="{{ $st.Params.chart.id}}" width="600" height="400"></canvas>-->
            <div id="chartInfo" class="chartInfo"></div>
        </div>
    {{ else }}
        {{ if eq $format "1"  }}
            <div class="col-12 col-lg-6">
                <!--<canvas id="{{ $st.Params.chart.id}}" width="600" height="400"></canvas>-->
                <div id="chartInfo" class="chartInfo"></div>
            </div>
            <div class="col-12 col-lg-6">
                {{ $st.Content }}
            </div>
        {{ else }}
            <div class="col-12 col-lg-6">
                {{ $st.Content }}
            </div>
            <div class="col-12 col-lg-6">
                <!--<canvas id="{{ $st.Params.chart.id}}" width="600" height="400"></canvas>-->
                <div id="chartInfo" class="chartInfo"></div>
            </div>
        {{ end }}
    {{ end }}
  {{ end }}
</div>
<script>

console.log("chart ");
    //console.log({{ $st.Content }});
    var id = {{ $st.Params.chart.id }};
    var text = {{ $st.Params.chart.text }};
    var label = {{$st.Params.chart.chart_label }};
    var backgroundColor = {{ $st.Params.chart.backgroundColor }};
    var borderColor = {{ $st.Params.chart.borderColor }};
    var borderWidth = {{ $st.Params.chart.borderWidth }};
    var yGridLines = {{ $st.Params.chart.yGridLines }};
    var xGridLines = {{ $st.Params.chart.xGridLines }};
    var chartData = {{ $st.Params.chart.data }};
    var test = {{ $st.Params.chart.id }};
    var json = {{ $st.Params.chart.json }};
    var canvasCount = 0;

    console.log(json);
    console.log(id);
    //console.log(label);
    //console.log(text);
    //console.log(chartData);
    //console.log("label: " + label + " backgroundColor: " + backgroundColor + " borderColor: " + borderColor + " borderWidth: " + borderWidth + " yGridLines: " + yGridLines + " xGridLines: " + xGridLines );

    //getJSON part
    $.getJSON(json, function (result) { 
        console.log("getJson");
        console.log(result);
        canvasCount = $('canvas').length;
        console.log(canvasCount);
        var num = 0;
        if(canvasCount == 0){
            var t_canvas = document.createElement("canvas");
            t_canvas.style.width = "600px";
            t_canvas.style.height = "400px";
            $(".chartInfo")[canvasCount].appendChild(t_canvas);
            var barChart = new Chart(t_canvas, result);

        } else if((canvasCount != 0)){
            var t_canvas = document.createElement("canvas");
            for(var i=0;i<canvasCount;i++){
                num++;
                t_canvas.style.width = "600px";
                t_canvas.style.height = "400px";
                $(".chartInfo")[num].appendChild(t_canvas);
                console.log("num: " + num);
            }
            var barChart = new Chart(t_canvas, result);
        }
    })
    .fail(function (jqxhr, status, error) { 
        console.log('alert', status, error) }
    );


    /*
    //the other choice
    canvasCount = $('canvas').length;
    console.log(canvasCount);
    var num = 0;
    if(canvasCount == 0){
        var t_canvas = document.createElement("canvas");
        t_canvas.style.width = "600px";
        t_canvas.style.height = "400px";
        $(".chartInfo")[canvasCount].appendChild(t_canvas);
        var chars = chartData.split(',');
        console.log(chars);

        var myMap = new Map();

        for(var i=0;i<chars.length;i++){
            var char = chars[i].split(':');
            console.log(char);
            for(var j=0;j<char.length;j++){
                myMap.set(char[0],char[1])
            }
        }

        const mapSort1 = new Map([...myMap.entries()].sort((a, b) => b[1] - a[1]));
        console.log(mapSort1);

        var t_arr1 =[];
        var t_arr2 = [];

        for(var [key,value] of mapSort1){
            //console.log(key + "," + value);
            t_arr1.push(key);
            t_arr2.push(value);
        }
        console.log(t_arr1);
        console.log(t_arr2);

        var chartData = {
          label: label,
          data: t_arr2,
          backgroundColor: backgroundColor,
          borderColor: borderColor,
          borderWidth: 2,
          hoverBorderWidth: 0
        };

        var chartOptions = {
          scales: {
            yAxes: [{
              categoryPercentage: 1.5,
              barPercentage: 0.5,
              gridLines: {
                display:false
              }
            }],
            xAxes: [{
              gridLines: {
                display:false
              }
            }],
          },
          elements: {
            rectangle: {
              borderSkipped: 'center',
            }
          },
          tooltips: {
            enabled: false
          },
          hover: {
              animationDuration: 0
          },
          plugins: {
            datalabels: {
                color: 'rgb(0,0,0)',
                anchor: 'end',
                align: 'end'                
            }
          }
        };

        var barChart = new Chart(t_canvas, {
          type: 'horizontalBar',
          data: {
            labels: t_arr1,
            datasets: [chartData],
          },
          options: chartOptions
        });

    } else if((canvasCount != 0)){

        var t_canvas = document.createElement("canvas");
        for(var i=0;i<canvasCount;i++){
            num++;
            t_canvas.style.width = "600px";
            t_canvas.style.height = "400px";
            $(".chartInfo")[num].appendChild(t_canvas);
            console.log("num: " + num);
        }
        var chars = chartData.split(',');
        console.log(chars);

        var myMap = new Map();

        for(var i=0;i<chars.length;i++){
            var char = chars[i].split(':');
            console.log(char);
            for(var j=0;j<char.length;j++){
                myMap.set(char[0],char[1])
            }
        }

        const mapSort1 = new Map([...myMap.entries()].sort((a, b) => b[1] - a[1]));
        console.log(mapSort1);

        var t_arr1 =[];
        var t_arr2 = [];

        for(var [key,value] of mapSort1){
            //console.log(key + "," + value);
            t_arr1.push(key);
            t_arr2.push(value);
        }
        console.log(t_arr1);
        console.log(t_arr2);

        var chartData = {
          label: label,
          data: t_arr2,
          backgroundColor: backgroundColor,
          borderColor: borderColor,
          borderWidth: 2,
          hoverBorderWidth: 0
        };

        var chartOptions = {
          scales: {
            yAxes: [{
              categoryPercentage: 1.5,
              barPercentage: 0.5,
              gridLines: {
                display:false
              }
            }],
            xAxes: [{
              gridLines: {
                display:false
              }
            }],
          },
          elements: {
            rectangle: {
              borderSkipped: 'center',
            }
          },
          tooltips: {
            enabled: false
          },
          hover: {
              animationDuration: 0
          },
          plugins: {
            datalabels: {
                color: 'rgb(0,0,0)',
                anchor: 'end',
                align: 'end'                
            }
          }
        };

        var barChart = new Chart(t_canvas, {
          type: 'horizontalBar',
          data: {
            labels: t_arr1,
            datasets: [chartData],
          },
          options: chartOptions
        });

    }
    */

</script>

testData.json

{   
    "type": "horizontalBar",
    "data": {
        "labels": ["apple", "banana", "orange", "lemon", "punch", "melon", "pear", "cherry", "mango", "strawberry", "coconut"],
        "datasets": [{
            "label": "fruit value",
            "data": ["23", "21", "19", "18", "17", "16", "16", "15", "11", "9", "9"],
            "backgroundColor": "rgba(255,207,47,0.6)",
            "borderColor": "rgba(255,207,47,0.6)",
            "borderWidth": "2",
            "hoverBorderWidth": "0"
        }]
    },
    "options": {
        "scales": {
            "yAxes": [{
                "categoryPercentage": "1.5",
                "barPercentage": "0.5",
                "gridLines": {
                    "display":false
                }
            }],
            "xAxes": [{
                "gridLines": {
                    "display":false
                }
            }]
        },
        "elements": {
            "rectangle": {
                "borderSkipped": "center"
            }
        },
        "tooltips": {
            "enabled": false
        },
        "hover": {
            "animationDuration": "0"
        },
        "plugins": {
            "datalabels": {
                "color": "rgb(0,0,0)",
                "anchor": "end",
                "align": "end"  
            }
        }
    }
}


This looks really good. I need to check this out. With all that code, is it
reasonable to make a short code?

On Tue, Jun 16, 2020 at 12:07 PM HACLLALEX notifications@github.com wrote:

I try to build a chart as a default theme using chartjs. I am using
Academia Hugo to be my main theme. Also, There are 3 file added including a
json, a theme html and a md.

In the markdown file, I have add a tag called "[chart]". User can thougth
this tag to get the new theme. In addition, I create 2 choices to generate
a chart. The first one is using JSON. the user just needs to put a json
into the tag called "json", then the chart will be generated. The second
one is using tag for insert or edit the chart detail. Details as follows:

chart.md

+++

A section created with the Chart widget.

widget = "chart" # See https://sourcethemes.com/academic/docs/page-builder/
headless = true # This file represents a page section.
active = true # Activate this widget? true/false
weight = 22 # Order that this section will appear.

Note: a full width section format can be enabled by commenting out the title and subtitle with a #.

title = "Chart"
subtitle = ""
[design]
# Choose how many columns the section has. Valid values: 1 or 2.
columns = "2"
format = "2" # Change the chart and text position. Valid values: 1 or 2.

[design.background]
# Apply a background color, gradient, or image.
# Uncomment (by removing #) an option to apply it.
# Choose a light or dark text color by setting text_color_light.
# Any HTML color name or Hex value is valid.

# Background color.
# color = "navy"

# Background gradient.
# gradient_start = "DeepSkyBlue"
# gradient_end = "SkyBlue"

# Background image.
# image = "image.jpg" # Name of image in static/img/.
# image_darken = 0.6 # Darken the image? Range 0-1 where 0 is transparent and 1 is opaque.

# Text color (true=light or false=dark).
# text_color_light = true

[design.spacing]
# Customize the section spacing. Order is top, right, bottom, left.
# padding = ["0px", "0px", "0px", "0px"]

[advanced]
# Custom CSS.
css_style = ""

# CSS class.
css_class = ""

[chart]
#2 Style for generate chart

#Using JSON to generate a chart
json="../json/testData3.json"

#Using tag to generate a chart
id = "myChart"
chart_label = "Source Rank"
backgroundColor = "rgba(255,207,47,0.6)"
borderColor = "rgba(255,207,47)"
borderWidth = "2"
yGridLines = "false"
xGridLines = "false"
type = ""
data = "a:1,b:2,c:3,d:4,e:5"

+++

In the html file, If you want to using the the second choice, you need to
uncomment the code first, and then comment the getjson part. Also, you need
to put the html file to the theme file first.

chart.html

{{ $st := .page }} {{ $columns := $st.Params.design.columns | default "2" }} {{ $format := $st.Params.design.format | default "1" }}
{{ if ne $columns "1" }}
{{ with $st.Title }}

{{ . | markdownify | emojify }}

{{ end }} {{ with $st.Params.subtitle }}

{{ . | markdownify | emojify }}

{{ end }}
{{ if eq $st.Content "" }}
  </div>
{{ else }} {{ if eq $format "1" }}
{{ $st.Content }}
{{ else }}
{{ $st.Content }}
{{ end }} {{ end }} {{ else }}
{{ with $st.Title }}

{{ . | markdownify | emojify }}

{{ end }} {{ with $st.Params.subtitle }}

{{ . | markdownify | emojify }}

{{ end }}
{{ if eq $st.Content "" }}
{{ else }} {{ if eq $format "1" }}
{{ $st.Content }}
{{ else }}
{{ $st.Content }}
{{ end }} {{ end }} {{ end }}

testData.json

{
"type": "horizontalBar",
"data": {
"labels": ["apple", "banana", "orange", "lemon", "punch", "melon", "pear", "cherry", "mango", "strawberry", "coconut"],
"datasets": [{
"label": "fruit value",
"data": ["23", "21", "19", "18", "17", "16", "16", "15", "11", "9", "9"],
"backgroundColor": "rgba(255,207,47,0.6)",
"borderColor": "rgba(255,207,47,0.6)",
"borderWidth": "2",
"hoverBorderWidth": "0"
}]
},
"options": {
"scales": {
"yAxes": [{
"categoryPercentage": "1.5",
"barPercentage": "0.5",
"gridLines": {
"display":false
}
}],
"xAxes": [{
"gridLines": {
"display":false
}
}]
},
"elements": {
"rectangle": {
"borderSkipped": "center"
}
},
"tooltips": {
"enabled": false
},
"hover": {
"animationDuration": "0"
},
"plugins": {
"datalabels": {
"color": "rgb(0,0,0)",
"anchor": "end",
"align": "end"
}
}
}
}

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/gcushen/hugo-academic/issues/1673#issuecomment-644668664,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAAJ2JVF33VGJTWOFBS3V7TRW475XANCNFSM4MVV2VFA
.

@HughP Thank you for the reply, I will try it. If there is any questions please feel free to let me know.

@HACLLALEX do you have a demonstration website working with this code? or a git repo? I'm trying to follow along on my own website. Is this chart designed to be on the main page (or some other page that uses widgets OR is this chart designed to be in a blog post, embedded in some sort of .md file (talk, course, project, etc)?

@HughP This is the git repo with this code.
The chart is designed to be a widgets.

html file location:

themes\academia-hugo\layouts\partials\widgetschart.html

markdown file location:

content\homechart.md

Json file location:

static\json

hope this helps

I make a shortcode to generate a chart by JSON and I have some update of my code.
For the shortcode, I add an HTML file and the location is

hugo-with-chartjs/layouts/shortcodes/chart.html

if you want to use this shortcode. You need to add the code like {{< chart id="[chartId]" json="[JSON]" >}} into the markdown file. Then, the Chart will be generated.

Simple location:

hugo-with-chartjs/content/home/shortcode.md

For the update of my code, To clearly for building chart. I rewrite the HTML file which is designed to be a widget. If you insert id and a JSON into each tag like

 [chart] 
 #Using JSON to generate a chart
 id = "myChart2"
 json="../json/testData4.json"

Then, the chart will be generated. Besides, I have kept the old version and the location will be

hugo-with-chartjs/themes/academia-hugo/layouts/partials/widgets/chart_16062020.html

my git repo is updated too. Please have a look at it.

@Bertbk

According to this new comment on Plotly repository, it is possible to load Plotly and MathJax v3. Has anyone tried this on Hugo + Academic?

https://github.com/plotly/plotly.js/issues/4563#issuecomment-647047186

@lucasfr It works like a charm! Thanks!

@gcushen Using plotly + MathJax 3 works with hugo+academic, provided this line is set before loading plotly (it's still kind of a hack...)

<script>
  window.PlotlyConfig = {MathJaxConfig: 'local'}
</script>

For others, if you are interested, this is part of my layouts/partials/custom_head.html file:

{{ if .Params.plotly }}
<script>
  window.PlotlyConfig = {MathJaxConfig: 'local'}
</script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
{{ end }}

A plotly = true parameters has to be set in the frontmatter of my markdown file where I want plotly to be displayed.

Thank you for the guidance, @Bertbk. Worked here too...

Hey, I and my team would like to give it a try if you allow us? @Bertbk @renegades12 @gcushen

Documentation and demo:

Possible future improvements (feel free to submit a PR):

  • show progress indicator whilst loading plot

Is this in the 4.8 branch or the 5.0 branch. The netify hosted Academic site which has documentation for the chart in it has the latest version as 4.8 but I would expect a new feature to be added to the WIP version... Which one do I need to clone?

Is this in the 4.8 branch or the 5.0 branch. The netify hosted Academic site which has documentation for the chart in it has the latest version as 4.8 but I would expect a new feature to be added to the WIP version... Which one do I need to clone?

You want to clone the latest master

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eduardohenriquearnold picture eduardohenriquearnold  Â·  4Comments

brianguay picture brianguay  Â·  4Comments

Framartin picture Framartin  Â·  4Comments

chris-prener picture chris-prener  Â·  3Comments

halfrost picture halfrost  Â·  3Comments