Proyecto Estación Meteorológica 4: Visualización de Resultados Mediante HTML y D3.js

Visualización de Resultados Mediante HTML y D3.js

Una vez se han subido los datos a ThingSpeak, tal y como se describe en el post anterior, se quiere visualizar el contenido que se ha subido. Para ello, se diseña una página web utilizando HTML, JavaScript, CSS y D3.js.

El código de la página consiste principalmente en 3 partes: la importación de datos y su tratamiento, la visualización de estos en una gráfica y la visualización en una tabla.

Primero, la importación de datos. Para ello, se debe conseguir una URI desde ThingSpeak, la cual se puede conseguir entrando en la pestaña “Data Import/Export” de los canales que se han creado, en la sección “Get a Channel Feed”. Se decide que se quieren recuperar 5 sets de datos desde cada canal, por lo que esto se tiene en cuenta a la hora de codificar las URIs. Se cargan los datos llamando a estas con JavaScript, las cuales, tras ser llamadas, ejecutan unas funciones previamente definidas. El cometido de estas funciones es la de guardar los datos recibidos en unas variables. En este caso, se reciben 3 tipos de datos desde ThingSpeak: la temperatura (en ºC), la humedad (en %) y el momento de cada lectura. Además, al haber 2 canales en total, se deben juntar todos los datos en una única variable para poder trabajar luego con ellos. Por esto, se hace una llamada extra a una de las URIs de ThingSpeak, con la cual se crea una variable cuyo tamaño es el doble de las otras dos; es decir, en la que se importarán 10 sets de datos. Esta variable se usará como esqueleto para juntar después todos los datos. Por último, todos los datos se juntan en la última variable creada utilizando un “for”. A la hora de juntar los datos, se tiene en cuenta que el último dato subido a la plataforma no tiene porqué estar en un canal específico, por lo que se comprueba primero en qué canal está el último dato, y de acuerdo a esto, se llena la variable en el orden correspondiente.

<!-- Scripts para guardar los datos en variables -->
<script type="text/javascript">
var jsonData;
function myCallback(dataWeGotViaJsonp) {
jsonData = dataWeGotViaJsonp['feeds'];
};
var jsonData1;
function myCallback1(dataWeGotViaJsonp) {
jsonData1 = dataWeGotViaJsonp['feeds'];
};
var jsonData2;
function myCallback2(dataWeGotViaJsonp) {
jsonData2 = dataWeGotViaJsonp['feeds'];
};
</script>
<!-- Llamadas a los canales de ThingSpeak para conseguir los datos -->
<!-- Conseguir las URIs desde el canal de ThingSpeak -> Data import / Export -> Get a Channel Feed -->
<!-- Al cargar los datos, ejecutar las funciones anteriores con "callback=myCallback" -->
<script type="text/javascript" src="https://api.thingspeak.com/channels/702692/feeds.json?results=10&callback=myCallback"></script>
<script type="text/javascript" src="https://api.thingspeak.com/channels/702692/feeds.json?results=5&callback=myCallback1"></script>
<script type="text/javascript" src="https://api.thingspeak.com/channels/702693/feeds.json?results=5&callback=myCallback2"></script>
<!-- Se juntan los datos recividos en una sola variable -->
<script type="text/javascript">
for (var j = 0; j < jsonData.length; j++) {
var r = j/2; <!-- Ya que j aumenta de dos en dos, se crea esta variable para los index de los datos originales -->
<!-- Dependiendo de cuales son los datos mas recientes, se llena la nueva matriz en un orden distinto -->
if (jsonData2[r]['created_at'] > jsonData1[r]['created_at']) {
jsonData[j]['created_at'] = jsonData1[r]['created_at'];
jsonData[j]['field1'] = jsonData1[r]['field1'];
jsonData[j]['field2'] = jsonData1[r]['field2'];
jsonData[j+1]['created_at'] = jsonData2[r]['created_at'];
jsonData[j+1]['field1'] = jsonData2[r]['field1'];
jsonData[j+1]['field2'] = jsonData2[r]['field2'];
} else {
jsonData[j]['created_at'] = jsonData2[r]['created_at'];
jsonData[j]['field1'] = jsonData2[r]['field1'];
jsonData[j]['field2'] = jsonData2[r]['field2'];
jsonData[j+1]['created_at'] = jsonData1[r]['created_at'];
jsonData[j+1]['field1'] = jsonData1[r]['field1'];
jsonData[j+1]['field2'] = jsonData1[r]['field2'];
}
j = j + 1;
}
</script>

Una vez se han importado los datos y se han tratado como es debido, se grafican. Para ello se utiliza D3.js. D3.js (Data-Driven Document) es una librería de JavaScript que sirve para manipular documentos basados en datos. Es decir, mediante esta librería se pueden crear diferentes tipos de gráficos utilizando tanto HTML, SVG y CSS.

Para ello, primero se carga la librería (en este caso se ha utilizado la v4). Esto permite usar la API que incorpora para definir, tanto las funciones, como los atributos de la imagen. Las funciones definidas aquí siempre tienen el prefijo “d3.”. Por ejemplo, para definir una línea se usa “d3.line”. Esta librería, aparte de aceptar sus propias funciones, también acepta las de los ya mencionados HTML, SVG y CSS.

Para hacer el gráfico, se empieza por definir la dimensión que ocupará este en la página web; es decir, sus márgenes. Dado que se tienen 2 variables, se definen 2 salidas: ‘y0’ para la temperatura e ‘y1’ para la humedad. La variable ‘x’ es el tiempo, que sirve para ambas salidas. Teniendo en cuenta lo anterior, se definen los rangos de las variables ‘x’, ‘y0’ e ‘y1’, los cuales se usarán varias veces más adelante. Seguidamente, se definen las líneas a graficar, una para la evolución de la temperatura y otra para la de la humedad, ambas en función del tiempo. Una vez definidos tanto los rangos, como las líneas, se define un objeto SVG. El SVG es un formato de gráficos vectoriales bidimensionales, tanto estáticos como animados, en formato XML. En este caso se usa para definir dónde estará situado el gráfico. También se definen las líneas de las cuadrículas para que quede más claro el gráfico.

<!-- Dibujar las gráficas con los datos de temperatura y la humedad -->
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 50, right: 100, bottom: 150, left: 100},
width = window.innerWidth - margin.left - margin.right - 30,
height = window.innerHeight - margin.top - margin.bottom - 130;
// parse the date / time
var parseDate = d3.timeFormat("%Y%m%d%H%M%S");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y0 = d3.scaleLinear().range([height, 0]);
var y1 = d3.scaleLinear().range([height, 0]);
// define the line of field1
var valueline = d3.line()
.curve(d3.curveMonotoneX) // apply smoothing to the line
.x(function(d) { return x(d.created_at); }) //Date
.y(function(d) { return y0(d.field1); }); // Temperature
// define the line of field2
var valueline2 = d3.line()
.curve(d3.curveMonotoneX) // apply smoothing to the line
.x(function(d) { return x(d.created_at); }) //Date
.y(function(d) { return y1(d.field2); }); // Humidity
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y0)
.ticks(5)
}

Una vez puesto a punto el espacio donde crear la gráfica, se define la función “draw”. Esta contiene los comandos necesarios para dibujar la gráfica. Tiene una única variable de entrada, la cual contiene la información de tiempo (momento en el que se creó cada dato), temperatura (°C) y humedad (%). Antes de empezar a graficar, se da formato a los datos de tiempo, temperatura y humedad, para que sea más fácil trabajar con ellos. Después, aunque los datos hayan sido previamente ordenados, se vuelven a ordenar en función del tiempo con el comando “sort”. Esto se hace por si ocurre alguna anomalía.

Como el rango de temperatura y humedad es variable, se extraen los máximos y mínimos de los datos y se define su dominio en función de estos. Así, se consigue que los gráficos estén ajustados a sus valores máximos y mínimos. Es decir, si los datos de temperatura van desde los 20°C a los 30°C, no tienen lógica que el dominio sea de 0°C a 100°C, ya que así, el usuario no será capaz de observar los detalles.

<script>
function draw(data) {
// format the data
data.forEach(function(d) {
// Creation date time for label
d.created_at = d3.isoParse(d.created_at);
d.field1 = +d.field1;
d.field2 = +d.field2;
});
// sort creation ascending
data.sort(function(a, b){
return a["created_at"]-b["created_at"];
})
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.created_at; }));
y0.domain([d3.min(data, function(d) { return Math.min(d.field1)-1; }),
d3.max(data, function(d) { return Math.max(d.field1)+1; })]);
y1.domain([d3.min(data, function(d) { return Math.min(d.field2)-3; }),
d3.max(data, function(d) { return Math.max(d.field2)+3; })]);

Una vez definidos los datos, rangos, líneas, etc. se dispone a dibujar la gráfica. Cada objeto que se añade se define como “svg.append” o anexado. De esta manera se añaden: las líneas de cuadrícula, las líneas de las funciones, los ejes y sus etiquetas y el título de la gráfica.

<script>
// add the X gridlines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
);
// add the Y gridlines
svg.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "lineRed")
.attr("d", valueline);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "lineBlue")
.attr("d", valueline2);
// Add the X Axis
svg.append("g")
.style('font-size', '14px')
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d %H:%M:%S")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// Add the text label for the x axis
//svg.append("text")
//.attr("transform", "translate(" + (width / 2) + " ," + (height + (margin.bottom*3/4)) + ")")
//.style('font-size', '20px')
//.style("text-anchor", "middle")
//.text("TIME");
// Add the Y0 Axis (Left)
svg.append("g")
.style('font-size', '14px')
.attr("class", "axisRed")
.call(d3.axisLeft(y0));
// text label for the y0 axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - (margin.left*3/4))
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("fill", "red")
.style('font-size', '20px')
.style("text-anchor", "middle")
.text("Temperatura (ºC)");
// Add the Y1 Axis (Right)
svg.append("g")
.style('font-size', '14px')
.attr("class", "axisSteelBlue")
.attr("transform", "translate( " + width + ", 0 )")
.call(d3.axisRight(y1));
// text label for the y1 axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", width + (margin.right/2))
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("fill", "steelblue")
.style('font-size', '20px')
.style("text-anchor", "middle")
.text("Humedad (%)");
// Graph title
svg.append('text')
.attr('x', (width / 2))
.attr('y', 0 - (margin.top / 3))
.attr('text-anchor', 'middle')
.style('font-size', '30px')
.text('CONDICIÓN CLIMÁTICA DEL HOGAR');
}

Solo queda llamar a la función. Para ello se escribe el nombre de la función y se le pasa la variable donde se encuentran los datos (en este caso “jsonData”). Por último, para que las demás estructuras del código puedan trabajar sin problemas con los mismos datos, se vuelve a cambiar el formato del dato de tiempo (“created_at”).

<script>
// Call de function
draw(jsonData);
// Change the format of the date to make it suitable for the table
jsonData.forEach(function(d) {
d.created_at = parseDate(d.created_at);
});
</script>

Por último, los datos se meten en una tabla. Esto cuenta con dos partes. Una de ellas es el HTML, el cual se encuentra en el “body” del código. Aquí se define la tabla como tal. La otra es el código JavaScript, el cual se encuentra en el “head”. Este actualiza los valores de la tabla con los datos recibidos en el orden correcto de lectura, además de cambiarles el formato a uno más intuitivo para facilitarle la comprensión al usuario.

<html>
<head>
<!-- Llenar tabla con los datos -->
<script type="text/javascript">
function tabla() {
for (var i = 9; i >= 0; i--) {
nom0 = "fecha" + (10 - i);
nom1 = "hora" + (10 - i);
nom2 = "temp" + (10 - i);
nom3 = "hum" + (10 - i);
<!-- Se le da un formato más "user friendly" a la fecha y la hora -->
tiempo = jsonData[i]['created_at'];
<!-- Se guardan los parámetros de la fecha en variables -->
dia = tiempo.substring(6, 8);
mes = tiempo.substring(4, 6);
ano = tiempo.substring(0, 4);
<!-- Se guardan los parámetros de la hora en variables -->
hora = tiempo.substring(8, 10);
minutos = tiempo.substring(10, 12);
segundos = tiempo.substring(12, 14);
<!-- Se adapta el formato de las variables de temperatura y humedad -->
temperatura = Number(jsonData[i]['field1']);
temperatura = temperatura.toFixed(0);
humedad = Number(jsonData[i]['field2']);
humedad = humedad.toFixed(0);
document.getElementById(nom0).innerHTML = dia + "/" + mes + "/" + ano;
document.getElementById(nom1).innerHTML = hora + ":" + minutos + ":" + segundos;
document.getElementById(nom2).innerHTML = temperatura + " &deg;C";
document.getElementById(nom3).innerHTML = humedad + " %";
}
}
</script>
</head>
<body>
<!-- Tabla con todos los datos -->
<div id="tabla">
<table>
<tr>
<th class='titulo'>Fecha</th>
<th class='titulo'>Hora</th>
<th class='titulo'>Temperatura</th>
<th class='titulo'>Humedad</th>
</tr>
<tr>
<th><div id="fecha1"></div></th>
<th><div id="hora1"></div></th>
<th><div id="temp1"></div></th>
<th><div id="hum1"></div></th>
</tr>
<tr>
<th><div id="fecha2"></div></th>
<th><div id="hora2"></div></th>
<th><div id="temp2"></div></th>
<th><div id="hum2"></div></th>
</tr>
<tr>
<th><div id="fecha3"></div></th>
<th><div id="hora3"></div></th>
<th><div id="temp3"></div></th>
<th><div id="hum3"></div></th>
</tr>
<tr>
<th><div id="fecha4"></div></th>
<th><div id="hora4"></div></th>
<th><div id="temp4"></div></th>
<th><div id="hum4"></div></th>
</tr>
<tr>
<th><div id="fecha5"></div></th>
<th><div id="hora5"></div></th>
<th><div id="temp5"></div></th>
<th><div id="hum5"></div></th>
</tr>
<tr>
<th><div id="fecha6"></div></th>
<th><div id="hora6"></div></th>
<th><div id="temp6"></div></th>
<th><div id="hum6"></div></th>
</tr>
<tr>
<th><div id="fecha7"></div></th>
<th><div id="hora7"></div></th>
<th><div id="temp7"></div></th>
<th><div id="hum7"></div></th>
</tr>
<tr>
<th><div id="fecha8"></div></th>
<th><div id="hora8"></div></th>
<th><div id="temp8"></div></th>
<th><div id="hum8"></div></th>
</tr>
<tr>
<th><div id="fecha9"></div></th>
<th><div id="hora9"></div></th>
<th><div id="temp9"></div></th>
<th><div id="hum9"></div></th>
</tr>
<tr>
<th><div id="fecha10"></div></th>
<th><div id="hora10"></div></th>
<th><div id="temp10"></div></th>
<th><div id="hum10"></div></th>
</tr>
</table>
</div>
</body>
</html>

Una vez juntado todo y añadiendole algunos detalles, como el CSS, por ejemplo, para configurar el aspecto visual de la página o unos botones para mostrar u ocultar la tabla, el código tiene el siguiente aspecto:

<html>
<head>
<meta charset="utf-8">
<title>Condición Climática del Hogar</title>
<link rel='shortcut icon' href='https://cdn4.iconfinder.com/data/icons/autumn-24/32/thermometer-autumn-humidity-fall-rain-temperature-measure-512.png' type='image/png'/>
<!-- Scripts para guardar los datos en variables -->
<script type="text/javascript">
var jsonData;
function myCallback(dataWeGotViaJsonp) {
jsonData = dataWeGotViaJsonp['feeds'];
};
var jsonData1;
function myCallback1(dataWeGotViaJsonp) {
jsonData1 = dataWeGotViaJsonp['feeds'];
};
var jsonData2;
function myCallback2(dataWeGotViaJsonp) {
jsonData2 = dataWeGotViaJsonp['feeds'];
};
</script>
<!-- Llamadas a los canales de ThingSpeak para conseguir los datos -->
<!-- Conseguir las URIs desde el canal de ThingSpeak -> Data import / Export -> Get a Channel Feed -->
<!-- Al cargar los datos, ejecutar las funciones anteriores con "callback=myCallback" -->
<script type="text/javascript" src="https://api.thingspeak.com/channels/702692/feeds.json?results=10&callback=myCallback"></script>
<script type="text/javascript" src="https://api.thingspeak.com/channels/702692/feeds.json?results=5&callback=myCallback1"></script>
<script type="text/javascript" src="https://api.thingspeak.com/channels/702693/feeds.json?results=5&callback=myCallback2"></script>
<!-- Se juntan los datos recividos en una sola variable -->
<script type="text/javascript">
for (var j = 0; j < jsonData.length; j++) {
var r = j/2; <!-- Ya que j aumenta de dos en dos, se crea esta variable para los index de los datos originales -->
<!-- Dependiendo de cuales son los datos mas recientes, se llena la nueva matriz en un orden distinto -->
if (jsonData2[r]['created_at'] > jsonData1[r]['created_at']) {
jsonData[j]['created_at'] = jsonData1[r]['created_at'];
jsonData[j]['field1'] = jsonData1[r]['field1'];
jsonData[j]['field2'] = jsonData1[r]['field2'];
jsonData[j+1]['created_at'] = jsonData2[r]['created_at'];
jsonData[j+1]['field1'] = jsonData2[r]['field1'];
jsonData[j+1]['field2'] = jsonData2[r]['field2'];
} else {
jsonData[j]['created_at'] = jsonData2[r]['created_at'];
jsonData[j]['field1'] = jsonData2[r]['field1'];
jsonData[j]['field2'] = jsonData2[r]['field2'];
jsonData[j+1]['created_at'] = jsonData1[r]['created_at'];
jsonData[j+1]['field1'] = jsonData1[r]['field1'];
jsonData[j+1]['field2'] = jsonData1[r]['field2'];
}
j = j + 1;
}
</script>
<!-- Llenar tabla con los datos -->
<script type="text/javascript">
function tabla() {
for (var i = 9; i >= 0; i--) {
nom0 = "fecha" + (10 - i);
nom1 = "hora" + (10 - i);
nom2 = "temp" + (10 - i);
nom3 = "hum" + (10 - i);
<!-- Se le da un formato más "user friendly" a la fecha y la hora -->
tiempo = jsonData[i]['created_at'];
<!-- Se guardan los parámetros de la fecha en variables -->
dia = tiempo.substring(6, 8);
mes = tiempo.substring(4, 6);
ano = tiempo.substring(0, 4);
<!-- Se guardan los parámetros de la hora en variables -->
hora = tiempo.substring(8, 10);
minutos = tiempo.substring(10, 12);
segundos = tiempo.substring(12, 14);
<!-- Se adapta el formato de las variables de temperatura y humedad -->
temperatura = Number(jsonData[i]['field1']);
temperatura = temperatura.toFixed(0);
humedad = Number(jsonData[i]['field2']);
humedad = humedad.toFixed(0);
document.getElementById(nom0).innerHTML = dia + "/" + mes + "/" + ano;
document.getElementById(nom1).innerHTML = hora + ":" + minutos + ":" + segundos;
document.getElementById(nom2).innerHTML = temperatura + " &deg;C";
document.getElementById(nom3).innerHTML = humedad + " %";
}
}
</script>
<!-- Hacer tabla visible/invisible -->
<script type="text/javascript">
function mostrar_tabla() {
<!-- Se llena la tabla -->
tabla();
document.getElementById("tabla").style.display = 'inline';
}
function ocultar_tabla() {
document.getElementById("tabla").style.display = 'none';
}
</script>
<!-- Se define el estilo de la tabla con css -->
<style>
div.contenedor {
position: relative;
margin: auto;
margin-top: 20px;
height: 50px;
width: 450px;
}
button {
width: 100%;
height: 100%;
border-radius: 8px;
color: white;
text-align: center;
font-size: 18px;
display: inline-block;
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
cursor: pointer;
}
button.mostrar {
background-color: #008CBA;
}
button.mostrar:hover {
background-color: #007399;
}
button.ocultar {
background-color: #555555;
}
button.ocultar:hover {
background-color: #333333;
}
table {
margin: auto;
margin-top: 10px;
}
tr, th {
width: 150px;
border-style: solid;
border-width: 1px;
border-color: black;
font-weight: normal;
}
th.titulo {
border-style: solid;
border-width: 3px;
border-color: black;
font-weight: bold;
}
/* Style the lines */
.lineBlue {
fill: none;
stroke: steelblue;
stroke-width: 3px;
}
.lineRed {
fill: none;
stroke: red;
stroke-width: 3px;
}
/* Style the axis*/
.axisSteelBlue text{
fill: steelblue;
}
.axisRed text{
fill: red;
}
/* Style the grids */
.grid line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
</style>
</head>
<body>
<!-- Dibujar las gráficas con los datos de temperatura y la humedad -->
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 50, right: 100, bottom: 150, left: 100},
width = window.innerWidth - margin.left - margin.right - 30,
height = window.innerHeight - margin.top - margin.bottom - 130;
// parse the date / time
var parseDate = d3.timeFormat("%Y%m%d%H%M%S");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y0 = d3.scaleLinear().range([height, 0]);
var y1 = d3.scaleLinear().range([height, 0]);
// define the line of field1
var valueline = d3.line()
.curve(d3.curveMonotoneX) // apply smoothing to the line
.x(function(d) { return x(d.created_at); }) //Date
.y(function(d) { return y0(d.field1); }); // Temperature
// define the line of field2
var valueline2 = d3.line()
.curve(d3.curveMonotoneX) // apply smoothing to the line
.x(function(d) { return x(d.created_at); }) //Date
.y(function(d) { return y1(d.field2); }); // Humidity
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// gridlines in x axis function
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// gridlines in y axis function
function make_y_gridlines() {
return d3.axisLeft(y0)
.ticks(5)
}
function draw(data) {
// format the data
data.forEach(function(d) {
// Creation date time for label
d.created_at = d3.isoParse(d.created_at);
d.field1 = +d.field1;
d.field2 = +d.field2;
});
// sort creation ascending
data.sort(function(a, b){
return a["created_at"]-b["created_at"];
})
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.created_at; }));
y0.domain([d3.min(data, function(d) { return Math.min(d.field1)-1; }),
d3.max(data, function(d) { return Math.max(d.field1)+1; })]);
y1.domain([d3.min(data, function(d) { return Math.min(d.field2)-3; }),
d3.max(data, function(d) { return Math.max(d.field2)+3; })]);
// add the X gridlines
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
);
// add the Y gridlines
svg.append("g")
.attr("class", "grid")
.call(make_y_gridlines()
.tickSize(-width)
.tickFormat("")
);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "lineRed")
.attr("d", valueline);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "lineBlue")
.attr("d", valueline2);
// Add the X Axis
svg.append("g")
.style('font-size', '14px')
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d %H:%M:%S")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// Add the text label for the x axis
//svg.append("text")
//.attr("transform", "translate(" + (width / 2) + " ," + (height + (margin.bottom*3/4)) + ")")
//.style('font-size', '20px')
//.style("text-anchor", "middle")
//.text("TIME");
// Add the Y0 Axis (Left)
svg.append("g")
.style('font-size', '14px')
.attr("class", "axisRed")
.call(d3.axisLeft(y0));
// text label for the y0 axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - (margin.left*3/4))
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("fill", "red")
.style('font-size', '20px')
.style("text-anchor", "middle")
.text("Temperatura (ºC)");
// Add the Y1 Axis (Right)
svg.append("g")
.style('font-size', '14px')
.attr("class", "axisSteelBlue")
.attr("transform", "translate( " + width + ", 0 )")
.call(d3.axisRight(y1));
// text label for the y1 axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", width + (margin.right/2))
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("fill", "steelblue")
.style('font-size', '20px')
.style("text-anchor", "middle")
.text("Humedad (%)");
// Graph title
svg.append('text')
.attr('x', (width / 2))
.attr('y', 0 - (margin.top / 3))
.attr('text-anchor', 'middle')
.style('font-size', '30px')
.text('CONDICIÓN CLIMÁTICA DEL HOGAR');
}
// Call de function
draw(jsonData);
// Change the format of the date to make it suitable for the table
jsonData.forEach(function(d) {
d.created_at = parseDate(d.created_at);
});
</script>
<!-- Botones para mostrar u ocultar la tabla -->
<div class="contenedor">
<div style="position:absolute;height:100%;width:150px;left:0px;top:0px;">
<button type="button" class="mostrar" onclick=mostrar_tabla()>Mostrar tabla</button>
</div>
<div style="position:absolute;height:100%;width:150px;right:0px;top:0px;">
<button type="button" class="ocultar" onclick=ocultar_tabla()>Ocultar tabla</button>
</div>
</div>
<!-- Tabla con todos los datos -->
<div id="tabla" style="display:none;">
<table>
<tr>
<th class='titulo'>Fecha</th>
<th class='titulo'>Hora</th>
<th class='titulo'>Temperatura</th>
<th class='titulo'>Humedad</th>
</tr>
<tr>
<th><div id="fecha1"></div></th>
<th><div id="hora1"></div></th>
<th><div id="temp1"></div></th>
<th><div id="hum1"></div></th>
</tr>
<tr>
<th><div id="fecha2"></div></th>
<th><div id="hora2"></div></th>
<th><div id="temp2"></div></th>
<th><div id="hum2"></div></th>
</tr>
<tr>
<th><div id="fecha3"></div></th>
<th><div id="hora3"></div></th>
<th><div id="temp3"></div></th>
<th><div id="hum3"></div></th>
</tr>
<tr>
<th><div id="fecha4"></div></th>
<th><div id="hora4"></div></th>
<th><div id="temp4"></div></th>
<th><div id="hum4"></div></th>
</tr>
<tr>
<th><div id="fecha5"></div></th>
<th><div id="hora5"></div></th>
<th><div id="temp5"></div></th>
<th><div id="hum5"></div></th>
</tr>
<tr>
<th><div id="fecha6"></div></th>
<th><div id="hora6"></div></th>
<th><div id="temp6"></div></th>
<th><div id="hum6"></div></th>
</tr>
<tr>
<th><div id="fecha7"></div></th>
<th><div id="hora7"></div></th>
<th><div id="temp7"></div></th>
<th><div id="hum7"></div></th>
</tr>
<tr>
<th><div id="fecha8"></div></th>
<th><div id="hora8"></div></th>
<th><div id="temp8"></div></th>
<th><div id="hum8"></div></th>
</tr>
<tr>
<th><div id="fecha9"></div></th>
<th><div id="hora9"></div></th>
<th><div id="temp9"></div></th>
<th><div id="hum9"></div></th>
</tr>
<tr>
<th><div id="fecha10"></div></th>
<th><div id="hora10"></div></th>
<th><div id="temp10"></div></th>
<th><div id="hum10"></div></th>
</tr>
</table>
</div>
</body>
</html>

Comentarios

Entradas populares de este blog

Proyecto Estación Meteorológica 3: Obtención y Envío de Datos Mediante Python

Diferentes técnicas de las redes neuronales