Normalize x values and log y values in d3.js - node.js

I am using Scatter plot to visualize data http://bl.ocks.org/mbostock/3887118. I have more than 2 graphs on a page. I want to keep two options where an user can select
1. Normalize button: Values at x-axes will get normalized and new graphs are plotted.
2. log y button: Values at y axes are changed to log y and new graphs are built on the same page accordingly.
How to do this d3.js?
Also I am plotting this using Nodejs, Express and d3.js.
Till now I have built the graphs. These are the options to increase interactivity.

I think the best is to define two different scales:
var yNormal = d3.scale.linear() ...
and
var yLog = d3.scale.log() ....
and on button click redraw the circles using the other scale:
//in button event handler
if( /* log */) {
svg.selectAll(".dot").attr('cy', function() { return yLog(d.yourDataField); }
}
else {
svg.selectAll(".dot").attr('cy', function() { return yNorm(d.yourDataField); }
}
You can also use transition to animate the redraw like this:
svg.selectAll(".dot").transition().duration(500).attr('cy', function() { return yLog(d.yourDataField); }
You can also animate the rescaling of the axis using this method.
You can apply the same to X axis as well.

Related

How to show all x-axis tick values in Plotly?

I am using this library
https://plot.ly/nodejs/axes/
to plot graphs in node.js. I have this code:
var data = [
{
x: xs,
y: ys,
type: "scatter"
}
];
var graphOptions = {filename: "date-axes", fileopt: "overwrite"};
plotly.plot(data, graphOptions, function (err, msg) {
console.log(msg);
console.log("DONE!");
});
to plot a graph with 5000 x-axis points. The problem is that in the rendered image, it x-axis values are not continuously increment by for each value I put. There is a rather large step, for example, if the x-axis labels are
['item1', 'item2', ..., 'item5000']
then it outputs with labels
['item1', 'item10', ..., 'item5000']
All the yaxis points are there, but I just want to see all x-axis labels.
Does anyone know what setting enables this? I assume that they did this by default so the text labels don't overlap each other, but in my case I want to see them all.
Thanks
I am using Python, though I have encountered the same problem. When you are specifying the layout of your chart, you need to set tickmode='linear', at least it worked for me!
import plotly
import plotly.plotly as py
import plotly.graph_objs as go
layout = go.Layout(
title='some title',
xaxis=dict(
title='Xaxis Name',
tickmode='linear')
Use layout.xaxis.dtick
Example here: https://plot.ly/nodejs/axes/
I run into the same problem and I managed to solve it: the trick is to define your values on xaxis as "categorical".
This is what my code looked like:
var layout = {
xaxis: {
tickangle: 35,
showticklabels: true,
type: 'category',
}
};
Plotly.newPlot(divname, data, layout);

Gradient text fill using GD - PHP

I need a function that renders gradient on a text using GD
something like
function gradientText($text,$font,$color1,$color2)
{
..
}
I suggest you try to build that function based your own needs.
You will want to center the text vertically/horizontal, change font size, etc...
Start on this function by Christopher Kramer, code is also below this answer...
http://www.php.net/manual/en/function.imagefill.php#93920
then you can use imagettfbbox if you want to use custom font files.
http://www.php.net/manual/en/function.imagettfbbox.php
Here is a sample image I generated using those 2 functions.
Pasting Chris' code of gradient here for reference:
<?php
function gradient($w=100, $h=100, $c=array('#FFFFFF','#FF0000','#00FF00','#0000FF'), $hex=true) {
/*
Generates a gradient image
Author: Christopher Kramer
Parameters:
w: width in px
h: height in px
c: color-array with 4 elements:
$c[0]: top left color
$c[1]: top right color
$c[2]: bottom left color
$c[3]: bottom right color
if $hex is true (default), colors are hex-strings like '#FFFFFF' (NOT '#FFF')
if $hex is false, a color is an array of 3 elements which are the rgb-values, e.g.:
$c[0]=array(0,255,255);
*/
$im=imagecreatetruecolor($w,$h);
if($hex) { // convert hex-values to rgb
for($i=0;$i<=3;$i++) {
$c[$i]=hex2rgb($c[$i]);
}
}
$rgb=$c[0]; // start with top left color
for($x=0;$x<=$w;$x++) { // loop columns
for($y=0;$y<=$h;$y++) { // loop rows
// set pixel color
$col=imagecolorallocate($im,$rgb[0],$rgb[1],$rgb[2]);
imagesetpixel($im,$x-1,$y-1,$col);
// calculate new color
for($i=0;$i<=2;$i++) {
$rgb[$i]=
$c[0][$i]*(($w-$x)*($h-$y)/($w*$h)) +
$c[1][$i]*($x *($h-$y)/($w*$h)) +
$c[2][$i]*(($w-$x)*$y /($w*$h)) +
$c[3][$i]*($x *$y /($w*$h));
}
}
}
return $im;
}
function hex2rgb($hex)
{
$rgb[0]=hexdec(substr($hex,1,2));
$rgb[1]=hexdec(substr($hex,3,2));
$rgb[2]=hexdec(substr($hex,5,2));
return($rgb);
}
// usage example
$image=gradient(300, 300, array('#000000', '#FFFFFF', '#FF0000', '#0000FF'));
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
Using GD
http://planetozh.com/blog/my-projects/images-php-gd-gradient-fill/ offers a class to create a gradient with GD.
Gradient can be linear (horizontal or vertical), radial, rectangle, diamond. That's the same options you would find on Adobe Photoshop.
The class methods fill rectangular areas with a gradient, so you could achieve a rather great gradient effect with the following method:
create a gradient rectangle with this class
write your text in the specified font
mix them:
you could cut the gradient picture with the shape of the text picture
you could apply the gradient picture as a pattern for the text picture
Using ImageMagick
Instead to use GD, I would use ImageMagick.
See http://www.imagemagick.org/Usage/fonts/#gradient for a sample of how to use ImageMagick to achieve that, and http://www.imagemagick.org/Usage/canvas/#gradient for all the gradients options.

How to manage event through a fill color with highchart?

I've got two series in an Highchart graph. Both are handling event like mousemove (to show tooltip) and mouse click.
Unfortunatly one of those series is an area serie which block any event to be triggered by the other one.
Let's say I've got those series with those plot options :
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function() {
alert ('Category: '+ this.category +', value: '+ this.y);
}
}
}
}
},
series: [{
color:'red',
data: [29.9, 51.5, 16.4, 19.2, 44.0, 16.0, 35.6, 48.5, 26.4, 4.1, 9.6, 54.4]
},
{
type:'area',
data: [39.9, 75.5, 120.4, 150.2, 130.0, 120.0, 140.6, 158.5, 216.4, 194.1, 95.6, 54.4]}
]
}
as seen in this JSFiddle
I can never click or see the tooltip on the red series points.
What I could do is to change the order of the series so the red one is over the blue one.
( like this). But I've got situations where I've got several area graphs over each other like that. In this case, change the order won't help.
Is there a way I can handle events through the fill area?
Ok I found a way that suit my need : manimulating SVG element order as indicated in this topic :
SVG re-ordering z-index (Raphael optional)
I'm using this code in the redraw event of the chart :
redraw : function(){
//get a reference on the first series svg element.
var svgSeriesParent = document.querySelectorAll('.highcharts-series')[0];
//loop on all the path drawn by highchart
var pathArray = document.querySelectorAll('path');
for (var pathIndex = 0; pathIndex < pathArray.length; pathIndex++) {
var pathObj = pathArray[pathIndex];
//if attribute fill is not "none", this is an area path.
if ($(pathObj).attr('fill') !== "none") {
//move the current fill path before the first series svg element.
svgSeriesParent.insertBefore(pathObj, svgSeriesParent.firstChild);
}
}
}
See the result in this JSFiddle
Limitation :
The fill area doesn't have the same svg group anymore thus, hidding / showing the series is broken : all the fill area are considered being part of the first series. (click in the legend to see it).
In my case I don't need to hide series so I'll go on with this solution.
The svg order manipulation is not complicated that's why I would expect highchart to manage this case : add a fillZIndex parametter doesn't seem difficult and could be pretty usefull...
Only what comes to my mind is using 4 series, 2 area and 2 lines and use index.
http://jsfiddle.net/j8qYK/3/

Flot draw additional vertical grid line

I can't get rid of vertical line in the end of graph.
I have replicated problem here:
http://jsfiddle.net/63BPw/4/
Color of grid lines is darkred and it's setted only in this part of js code:
grid: {
aboveData: false,
hoverable: true,
clickable: true,
color: "darkred",
borderWidth: {
top: 0,
bottom: 1,
left: 0,
right: 0
}
}
Console do not throw any errors. I don't use any margins from inside javascript file or external css files.
I think this is probably a bug.
The problem isn't in your grid setup, but in the drawing of each axis. Specifically, you setup 2 y-axes, one on the left and one on the right. Deep in the flot code, it decides whether to draw a "bar" to attach the ticks to based on whether the axis is the "innermost" or not. When you have 2 yaxes, it is incorrectly deciding that your right-positioned yaxis is not innermost, and therefore drawing a tick bar.
Relevant code, both bits are called per-axis:
In allocateAxisBoxFirstPhase:
/*note this is only called for axes that have tickLength set
but later it is checked as true/false, not undefined
(which is what you'd get if you set your yaxis tickLength = 0) */
var sameDirection = $.grep(all, function (a) {
return a && a.reserveSpace;
});
innermost = $.inArray(axis, sameDirection) == 0;
In drawGrid:
if (!axis.innermost) {
//in here it draws the tick bar
}
Workaround:
Find that !axis.innermost bit and change it to axis.innermost == false. Set tickLength = 0 in your 2nd yaxis. That's it.
I've implemented those two changes here: http://jsfiddle.net/63BPw/5/
Also, FYI I filed a bug about this: https://github.com/flot/flot/issues/1056

Flot reset zoom

I'm using Flot Charts with mouse scroll to zoom in and out. I created a button to call zoomOut() and it works well, but I can't find any solution to how I can zoom out all the way so that it Looks just like when it was first loaded. I don't want to reload that who container because it using ajax to pull data from mysql on refresh.
I Googled but couldn't find anything.
You can also set a double click to reset the zoom function of the Flot chart. It redraws the Flot chart to its original state and can be used with dynamic data.
$("#placeholder").dblclick(function () {
plot = $.plot(placeholder, dataset, options);
});
You can set the ranges of the axes to null. By setting this, the zoom level will be set so every data point is visible, just like the default zoom level.
Unlike the other solutions, this solution will not construct a whole new plot.
var axes = plot.getAxes(),
xaxis = axes.xaxis.options,
yaxis = axes.yaxis.options;
xaxis.min = null;
xaxis.max = null;
yaxis.min = null;
yaxis.max = null;
// Don't forget to redraw the plot
plot.setupGrid();
plot.draw();
You can save your initial ranges of axes and redraw your plot like in example for navigating. But your code will be look like these:
// do the zooming
plotObjectPointer = $.plot(placeholder, plotData,
$.extend(true, {}, options, {
xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
}));
where ranges will be your initial ranges. To prevent repeated Ajax loading you can use window.localStorage or just another var for storing plotData.

Resources