HugoBlox / hugo-blox-builder

🚨 GROW YOUR AUDIENCE WITH HUGOBLOX! 🚀 HugoBlox is an easy, fast no-code website builder for researchers, entrepreneurs, data scientists, and developers. Build stunning sites in minutes. 适合研究人员、企业家、数据科学家和开发者的简单快速无代码网站构建器。用拖放功能、可定制模板和内置SEO工具快速创建精美网站!
https://hugoblox.com/templates/
MIT License
8.2k stars 2.9k forks source link

Add data visualization feature #1673

Closed renegades12 closed 4 years ago

renegades12 commented 4 years ago

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

luiscachog commented 4 years ago

+1 on this feature!!

gcushen commented 4 years ago

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?

YonghuiDong commented 4 years ago

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

renegades12 commented 4 years ago

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

YonghuiDong commented 4 years ago

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

Bertbk commented 4 years ago

@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

HughP commented 4 years ago

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.

Bertbk commented 4 years ago

@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.

lucasfr commented 4 years ago

@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.

Bertbk commented 4 years ago

@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... :)

lucasfr commented 4 years ago

@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.

Bertbk commented 4 years ago

going back to MathJaxV2

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

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.

lucasfr commented 4 years ago

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

Bertbk commented 4 years ago

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

HACLLALEX commented 4 years ago

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/chart.js@2.8.0"></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"  
            }
        }
    }
}
HughP commented 4 years ago

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 "" }}
{{ 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 .

HACLLALEX commented 4 years ago

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

HughP commented 4 years ago

@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)?

HACLLALEX commented 4 years ago

@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\widgets\chart.html

markdown file location:

content\home\chart.md

Json file location:

static\json

hope this helps

HACLLALEX commented 4 years ago

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.

lucasfr commented 4 years ago

@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

Bertbk commented 4 years ago

@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.

lucasfr commented 4 years ago

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

aashigupta19 commented 4 years ago

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

gcushen commented 4 years ago

Documentation and demo:

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

HughP commented 4 years ago

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?

rodrigoalcarazdelaosa commented 4 years ago

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