更新:添加了一个在线工作小提琴添加了一个工作代码片段:)
我正在从
dygraphs
移动到chartsjs
,但我一直试图在对数刻度图表中显示较小的网格线。带有 chartjs
的图表位于下面第一张图片中(没有小网格线)。我希望它有像第二张图片中那样的网格线。多次阅读文档并没有给我带来答案。
const termFreqWithChartjs = (ctx, series, term, termFreq) => {
const config = {
type: 'line',
data: {
labels: termFreq.map(e => e.journalYear),
datasets: [
{
label: series.y1,
data: termFreq.map(e => e.total),
borderColor: 'red',
borderWidth: 1,
backgroundColor: 'rgba(255, 0, 0, 0.1)',
pointStyle: 'circle',
pointRadius: 3,
pointBorderColor: 'rgb(0, 0, 0)'
},
{
label: series.y2,
data: termFreq.map(e => e.withImages),
borderColor: 'blue',
borderWidth: 1,
backgroundColor: 'rgba(0, 0, 255, 0.1)',
pointStyle: 'circle',
pointRadius: 3,
pointBorderColor: 'rgb(0, 0, 0)'
}
]
},
options: {
interaction: {
intersect: false,
mode: 'x',
},
animation: false,
responsive: true,
scales: {
x: {
display: true,
},
y: {
display: true,
type: 'logarithmic',
grid: {
borderColor: 'grey',
tickColor: 'grey'
},
min: 1,
ticks: {
callback: function (value, index, values) {
if (value === 1000000) return "1M";
if (value === 100000) return "100K";
if (value === 10000) return "10K";
if (value === 1000) return "1K";
if (value === 100) return "100";
if (value === 10) return "10";
if (value === 1) return "1";
return null;
}
}
}
},
plugins: {
title: {
display: true,
text: `occurrence of '${term}' in text by year`,
},
legend: {
display: true,
position: 'chartArea',
labels: {
usePointStyle: true,
}
},
tooltip: {
enabled: true
}
}
}
};
let canvas = document.getElementById('termFreq');
if (canvas) {
termFreqChart.destroy();
termFreqChart = new Chart(canvas, config);
}
else {
canvas = document.createElement('canvas');
canvas.id = "termFreq";
canvas.width = 500;
canvas.height = 200;
ctx.appendChild(canvas);
termFreqChart = new Chart(canvas, config);
}
}
const termFreq = [
{
"journalYear": 1841,
"total": 3,
"withImages": 0
},
{
"journalYear": 1846,
"total": 2,
"withImages": 0
},
{
"journalYear": 1850,
"total": 2,
"withImages": 0
},
{
"journalYear": 1851,
"total": 26,
"withImages": 0
},
{
"journalYear": 1853,
"total": 5,
"withImages": 0
},
{
"journalYear": 1855,
"total": 7,
"withImages": 0
},
{
"journalYear": 1857,
"total": 27,
"withImages": 0
},
{
"journalYear": 1859,
"total": 30,
"withImages": 0
},
{
"journalYear": 1860,
"total": 4,
"withImages": 0
},
{
"journalYear": 1861,
"total": 9,
"withImages": 0
},
{
"journalYear": 1862,
"total": 18,
"withImages": 0
},
{
"journalYear": 1863,
"total": 4,
"withImages": 0
},
{
"journalYear": 1866,
"total": 12,
"withImages": 0
},
{
"journalYear": 1877,
"total": 1,
"withImages": 0
},
{
"journalYear": 1884,
"total": 2,
"withImages": 0
},
{
"journalYear": 1886,
"total": 12,
"withImages": 0
},
{
"journalYear": 1887,
"total": 2,
"withImages": 0
},
{
"journalYear": 1890,
"total": 5,
"withImages": 0
},
{
"journalYear": 1893,
"total": 4,
"withImages": 0
},
{
"journalYear": 1894,
"total": 9,
"withImages": 0
},
{
"journalYear": 1895,
"total": 3,
"withImages": 0
},
{
"journalYear": 1896,
"total": 1,
"withImages": 0
},
{
"journalYear": 1902,
"total": 3,
"withImages": 0
},
{
"journalYear": 1904,
"total": 14,
"withImages": 0
},
{
"journalYear": 1905,
"total": 10,
"withImages": 0
},
{
"journalYear": 1910,
"total": 1,
"withImages": 0
},
{
"journalYear": 1912,
"total": 1,
"withImages": 0
},
{
"journalYear": 1913,
"total": 3,
"withImages": 0
},
{
"journalYear": 1914,
"total": 7,
"withImages": 0
},
{
"journalYear": 1915,
"total": 5,
"withImages": 0
},
{
"journalYear": 1920,
"total": 1,
"withImages": 0
},
{
"journalYear": 1922,
"total": 8,
"withImages": 0
},
{
"journalYear": 1924,
"total": 1,
"withImages": 0
},
{
"journalYear": 1926,
"total": 5,
"withImages": 0
},
{
"journalYear": 1928,
"total": 5,
"withImages": 0
},
{
"journalYear": 1932,
"total": 2,
"withImages": 0
},
{
"journalYear": 1949,
"total": 3,
"withImages": 0
},
{
"journalYear": 1950,
"total": 1,
"withImages": 0
},
{
"journalYear": 1953,
"total": 2,
"withImages": 0
},
{
"journalYear": 1955,
"total": 3,
"withImages": 0
},
{
"journalYear": 1956,
"total": 1,
"withImages": 0
},
{
"journalYear": 1958,
"total": 2,
"withImages": 0
},
{
"journalYear": 1959,
"total": 1,
"withImages": 0
},
{
"journalYear": 1960,
"total": 2,
"withImages": 0
},
{
"journalYear": 1975,
"total": 2,
"withImages": 0
},
{
"journalYear": 1979,
"total": 136,
"withImages": 0
},
{
"journalYear": 1990,
"total": 27,
"withImages": 5
},
{
"journalYear": 1992,
"total": 3,
"withImages": 0
},
{
"journalYear": 1993,
"total": 1,
"withImages": 0
},
{
"journalYear": 1997,
"total": 1,
"withImages": 1
},
{
"journalYear": 2000,
"total": 251,
"withImages": 225
},
{
"journalYear": 2001,
"total": 14,
"withImages": 0
},
{
"journalYear": 2003,
"total": 141,
"withImages": 139
},
{
"journalYear": 2004,
"total": 2,
"withImages": 0
},
{
"journalYear": 2005,
"total": 62,
"withImages": 0
},
{
"journalYear": 2006,
"total": 16,
"withImages": 12
},
{
"journalYear": 2007,
"total": 79,
"withImages": 17
},
{
"journalYear": 2008,
"total": 42,
"withImages": 16
},
{
"journalYear": 2009,
"total": 141,
"withImages": 60
},
{
"journalYear": 2010,
"total": 111,
"withImages": 5
},
{
"journalYear": 2011,
"total": 62,
"withImages": 14
},
{
"journalYear": 2012,
"total": 100,
"withImages": 25
},
{
"journalYear": 2013,
"total": 137,
"withImages": 129
},
{
"journalYear": 2014,
"total": 54,
"withImages": 23
},
{
"journalYear": 2015,
"total": 139,
"withImages": 73
},
{
"journalYear": 2016,
"total": 166,
"withImages": 36
},
{
"journalYear": 2017,
"total": 87,
"withImages": 74
},
{
"journalYear": 2018,
"total": 79,
"withImages": 49
},
{
"journalYear": 2019,
"total": 142,
"withImages": 96
},
{
"journalYear": 2020,
"total": 84,
"withImages": 27
},
{
"journalYear": 2021,
"total": 907,
"withImages": 386
},
{
"journalYear": 2022,
"total": 79,
"withImages": 50
},
{
"journalYear": 2023,
"total": 3,
"withImages": 0
}
];
const series = {
x: "journal year",
y1: "total",
y2: "with images"
}
const ctx = document.getElementById('graphdiv');
termFreqWithChartjs(ctx, series, 'formica', termFreq);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div id="graphdiv"></div>
Chart.js 默认情况下会生成对数轴的小网格线。 OP 的代码不显示任何小网格线,因为
ticks.callback
函数对于不合格的刻度返回 null
;这会导致网格线的刻度 和 被删除。
一个可能的解决方案是在
return null
中将return ''
替换为ticks.callback
;这会保留刻度线(和网格线),但不显示标签。一个缺点是,即使标签的大小为零,系统也会为其分配空间,这可能会影响标记的刻度;人们可能想禁用 ticks.autoSkip: false
。
之后,真正的挑战是在视觉上区分次要网格线和主要网格线。该解决方案来自这样一个事实:大多数网格线设置都是可编写脚本的选项,可以分配函数,有助于使结果(选项,例如网格线颜色)适应运行时环境 - 在这种情况下,取决于是否对应勾选是次要还是主要。
我在下面的代码中标识了所有相关选项,这些选项可用于在视觉上区分次要网格线和刻度与主要网格线和刻度。您可以只保留其中一些,也可以不保留。
我还在函数
options.scales.y.afterBuildTicks
中添加了一个可能的刻度过滤器,更多地演示了该功能。还可以通过实际返回某些 ticks.callback
的 null
来过滤 value
中的网格线。
选项,提取:
const config = {
type: 'line',
data: {
// ............
},
options: {
// ..... other options
scales: {
x: // .....
y: {
display: true,
type: 'logarithmic',
grid: {
tickColor: function(data){ // color of the tick line
return data.tick.major ? 'rgb(196, 196, 196)' :
'rgba(196, 196, 196, 0)' // minor ticks not visible
},
lineWidth: function(data){ // the width of grid line
return data.tick.major ? 2 : 1
},
color:function(data){ // the color of the grid line
return data.tick.major ? 'rgb(196, 196, 196)' :
'rgba(196, 196, 196, 0.5)'
}
},
border:{
dash:function(data){
// dash pattern for grid lines
// (unexpected position for this option here)
return data.tick.major ? null : [5, 1]
}
},
min: 1,
afterBuildTicks: function(ax){
ax.ticks = ax.ticks.filter(({value})=>{
const r = value/ Math.pow(10, Math.floor(Math.log10(value)+1e-5));
return Math.abs(r - Math.round(r)) < 1e-5
})
// this eliminates tick values like 15 or 150 and only keeps
// those of the form n*10^m with n, m one digit integers
// this might not be necessary
},
ticks: {
callback: function (value, index, ticks) {
if (value === 1000000) return "1M";
if (value === 100000) return "100K";
if (value === 10000) return "10K";
if (value === 1000) return "1K";
if (value === 100) return "100";
if (value === 10) return "10";
if (value === 1) return "1";
return '';
}
}
}
},
// ......
}
}
完整的运行示例,从 OP 分叉,高度增加以使日志小网格线可见。
const termFreqWithChartjs = (ctx, series, term, termFreq) => {
const config = {
type: 'line',
data: {
labels: termFreq.map(e => e.journalYear),
datasets: [
{
label: series.y1,
data: termFreq.map(e => e.total),
borderColor: 'red',
borderWidth: 1,
backgroundColor: 'rgba(255, 0, 0, 0.1)',
pointStyle: 'circle',
pointRadius: 3,
pointBorderColor: 'rgb(0, 0, 0)'
},
{
label: series.y2,
data: termFreq.map(e => e.withImages),
borderColor: 'blue',
borderWidth: 1,
backgroundColor: 'rgba(0, 0, 255, 0.1)',
pointStyle: 'circle',
pointRadius: 3,
pointBorderColor: 'rgb(0, 0, 0)'
}
]
},
options: {
interaction: {
intersect: false,
mode: 'x',
},
animation: false,
responsive: true,
scales: {
x: {
display: true,
},
y: {
display: true,
type: 'logarithmic',
grid: {
tickColor: function(data){
return data.tick.major ? 'rgb(196, 196, 196)' :
'rgba(196, 196, 196, 0)' // minor ticks not visible
},
lineWidth: function(data){
return data.tick.major ? 2 : 1
},
color:function(data){
return data.tick.major ? 'rgb(196, 196, 196)' :
'rgba(196, 196, 196, 0.5)'
}
},
border:{
dash:function(data){
// dash line for grid lines
// (unexpected position for this option here)
return data.tick.major ? null : [5, 1]
}
},
min: 1,
afterBuildTicks: function(ax){
ax.ticks = ax.ticks.filter(({value})=>{
const r = value/ Math.pow(10, Math.floor(Math.log10(value)+1e-5));
return Math.abs(r - Math.round(r)) < 1e-5
})
// this eliminates tick values like 15 or 150 and only keeps
// those of the form n*10^m with n, m one digit integers
// this might not be necessary
},
ticks: {
autoSkip: false,
callback: function (value, index, ticks) {
if (value === 1000000) return "1M";
if (value === 100000) return "100K";
if (value === 10000) return "10K";
if (value === 1000) return "1K";
if (value === 100) return "100";
if (value === 10) return "10";
if (value === 1) return "1";
return '';
}
}
}
},
plugins: {
title: {
display: true,
text: `occurrence of '${term}' in text by year`,
},
legend: {
display: true,
position: 'chartArea',
labels: {
usePointStyle: true,
}
},
tooltip: {
enabled: true
}
}
}
};
let canvas = document.getElementById('termFreq');
if (canvas) {
termFreqChart.destroy();
termFreqChart = new Chart(canvas, config);
}
else {
canvas = document.createElement('canvas');
canvas.id = "termFreq";
canvas.width = 960;
canvas.height = 600;
ctx.appendChild(canvas);
termFreqChart = new Chart(canvas, config);
}
}
const termFreq = [
{
"journalYear": 1841,
"total": 3,
"withImages": 0
},
{
"journalYear": 1846,
"total": 2,
"withImages": 0
},
{
"journalYear": 1850,
"total": 2,
"withImages": 0
},
{
"journalYear": 1851,
"total": 26,
"withImages": 0
},
{
"journalYear": 1853,
"total": 5,
"withImages": 0
},
{
"journalYear": 1855,
"total": 7,
"withImages": 0
},
{
"journalYear": 1857,
"total": 27,
"withImages": 0
},
{
"journalYear": 1859,
"total": 30,
"withImages": 0
},
{
"journalYear": 1860,
"total": 4,
"withImages": 0
},
{
"journalYear": 1861,
"total": 9,
"withImages": 0
},
{
"journalYear": 1862,
"total": 18,
"withImages": 0
},
{
"journalYear": 1863,
"total": 4,
"withImages": 0
},
{
"journalYear": 1866,
"total": 12,
"withImages": 0
},
{
"journalYear": 1877,
"total": 1,
"withImages": 0
},
{
"journalYear": 1884,
"total": 2,
"withImages": 0
},
{
"journalYear": 1886,
"total": 12,
"withImages": 0
},
{
"journalYear": 1887,
"total": 2,
"withImages": 0
},
{
"journalYear": 1890,
"total": 5,
"withImages": 0
},
{
"journalYear": 1893,
"total": 4,
"withImages": 0
},
{
"journalYear": 1894,
"total": 9,
"withImages": 0
},
{
"journalYear": 1895,
"total": 3,
"withImages": 0
},
{
"journalYear": 1896,
"total": 1,
"withImages": 0
},
{
"journalYear": 1902,
"total": 3,
"withImages": 0
},
{
"journalYear": 1904,
"total": 14,
"withImages": 0
},
{
"journalYear": 1905,
"total": 10,
"withImages": 0
},
{
"journalYear": 1910,
"total": 1,
"withImages": 0
},
{
"journalYear": 1912,
"total": 1,
"withImages": 0
},
{
"journalYear": 1913,
"total": 3,
"withImages": 0
},
{
"journalYear": 1914,
"total": 7,
"withImages": 0
},
{
"journalYear": 1915,
"total": 5,
"withImages": 0
},
{
"journalYear": 1920,
"total": 1,
"withImages": 0
},
{
"journalYear": 1922,
"total": 8,
"withImages": 0
},
{
"journalYear": 1924,
"total": 1,
"withImages": 0
},
{
"journalYear": 1926,
"total": 5,
"withImages": 0
},
{
"journalYear": 1928,
"total": 5,
"withImages": 0
},
{
"journalYear": 1932,
"total": 2,
"withImages": 0
},
{
"journalYear": 1949,
"total": 3,
"withImages": 0
},
{
"journalYear": 1950,
"total": 1,
"withImages": 0
},
{
"journalYear": 1953,
"total": 2,
"withImages": 0
},
{
"journalYear": 1955,
"total": 3,
"withImages": 0
},
{
"journalYear": 1956,
"total": 1,
"withImages": 0
},
{
"journalYear": 1958,
"total": 2,
"withImages": 0
},
{
"journalYear": 1959,
"total": 1,
"withImages": 0
},
{
"journalYear": 1960,
"total": 2,
"withImages": 0
},
{
"journalYear": 1975,
"total": 2,
"withImages": 0
},
{
"journalYear": 1979,
"total": 136,
"withImages": 0
},
{
"journalYear": 1990,
"total": 27,
"withImages": 5
},
{
"journalYear": 1992,
"total": 3,
"withImages": 0
},
{
"journalYear": 1993,
"total": 1,
"withImages": 0
},
{
"journalYear": 1997,
"total": 1,
"withImages": 1
},
{
"journalYear": 2000,
"total": 251,
"withImages": 225
},
{
"journalYear": 2001,
"total": 14,
"withImages": 0
},
{
"journalYear": 2003,
"total": 141,
"withImages": 139
},
{
"journalYear": 2004,
"total": 2,
"withImages": 0
},
{
"journalYear": 2005,
"total": 62,
"withImages": 0
},
{
"journalYear": 2006,
"total": 16,
"withImages": 12
},
{
"journalYear": 2007,
"total": 79,
"withImages": 17
},
{
"journalYear": 2008,
"total": 42,
"withImages": 16
},
{
"journalYear": 2009,
"total": 141,
"withImages": 60
},
{
"journalYear": 2010,
"total": 111,
"withImages": 5
},
{
"journalYear": 2011,
"total": 62,
"withImages": 14
},
{
"journalYear": 2012,
"total": 100,
"withImages": 25
},
{
"journalYear": 2013,
"total": 137,
"withImages": 129
},
{
"journalYear": 2014,
"total": 54,
"withImages": 23
},
{
"journalYear": 2015,
"total": 139,
"withImages": 73
},
{
"journalYear": 2016,
"total": 166,
"withImages": 36
},
{
"journalYear": 2017,
"total": 87,
"withImages": 74
},
{
"journalYear": 2018,
"total": 79,
"withImages": 49
},
{
"journalYear": 2019,
"total": 142,
"withImages": 96
},
{
"journalYear": 2020,
"total": 84,
"withImages": 27
},
{
"journalYear": 2021,
"total": 907,
"withImages": 386
},
{
"journalYear": 2022,
"total": 79,
"withImages": 50
},
{
"journalYear": 2023,
"total": 3,
"withImages": 0
}
];
const series = {
x: "journal year",
y1: "total",
y2: "with images"
}
const ctx = document.getElementById('graphdiv');
termFreqWithChartjs(ctx, series, 'formica', termFreq);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div id="graphdiv"></div>