This is what I currently have:
What I need, is to have the following uneven intervals (vertical lines & x-axis labels):
1) 1 (i.e. must not cross at 0)
2) 1.5
3) 2.5
4) 3.5
5) 4
Is there any way to do this? Even if it's a kludge with an extra series or something - although I'm hoping it's something to do with IntervalOffset, but I can't get it to do what I want.
Currently, I just have:
chartarea.AxisX.Maximum = 4;
chartarea.AxisX.Minimum = 1;
chartarea.AxisX.Interval = 1;
This is what was required:
// set the max & min, with an interval of 1 which is offset by 0.5
// this gives the correct start (1), and three .5 intervals
// however, it doesn't give the closing vertical line at 4
chartarea.AxisX.Maximum = 4;
chartarea.AxisX.Minimum = 1;
chartarea.AxisX.Interval = 1;
chartarea.AxisX.IntervalOffset = 0.5;
// enable a secondary y axis for the line at 4
chartarea.AxisY2.Enabled = AxisEnabled.True;
// switch of all tickmarks & gridlines
chartarea.AxisY2.MajorTickMark.Enabled = false;
chartarea.AxisY2.MinorTickMark.Enabled = false;
chartarea.AxisY2.MajorGrid.Enabled = false;
chartarea.AxisY2.MinorGrid.Enabled = false;
chartarea.AxisY2.LabelStyle.Enabled = false;
// set the correct colour & line style
chartarea.AxisY2.LineColor = Color.FromArgb(160, 160, 160);
chartarea.AxisY2.LineDashStyle = ChartDashStyle.Dash;
// add custom labels for the 5 points/lines
chartarea.AxisX.CustomLabels.Add(0.9, 1.1, "1");
chartarea.AxisX.CustomLabels.Add(1.4, 1.6, "1.5");
chartarea.AxisX.CustomLabels.Add(2.4, 2.6, "2.5");
chartarea.AxisX.CustomLabels.Add(3.4, 3.6, "3.5");
chartarea.AxisX.CustomLabels.Add(3.9, 4.1, "4");
And voila:
(although my data has changed)
Related
I am working QCustomPlot with Qt and need to change the color of a particular vertical grid line within the graph please let us know how we can change that I attached the image of my requirement.
The bleo code solve the issue
GraphTesting(QCustomPlot * customPlot)
{
// generate some data:
QVector<double> x(101), y(101); // initialize with entries 0..100
for (int i = 0; i < 101; ++i)
{
x[i] = i; //i / 50.0 - 1; // x goes from -1 to 1
y[i] = x[i]/2; // let's plot a quadratic function
}
// create graph and assign data to it:
customPlot->addGraph();
customPlot->graph(0)->setData(x, y);
// give the axes some labels:
customPlot->xAxis->setLabel("x");
customPlot->yAxis->setLabel("y");
customPlot->rescaleAxes();
QCPItemLine *step = new QCPItemLine(customPlot);
step->setPen(QPen(QColor(140, 0, 0)));
double begin = 25;
double first = customPlot->yAxis->range().lower;
double end = customPlot->yAxis->range().upper; //example values
step->start->setCoords(begin, first);
step->end->setCoords(begin, end);
customPlot->replot();
}
two question. first off, how could I set a particular value in a 3d texture to 1, lets say the y coordinate of the element at index 1,1,1 in the following Int16Array so I could later read it. I think it'd go something like this:
var data = new Int16Array(size * size * size);
data.fill(0);
// ??? (somehow I'd set values of the data array at index 1,1,1 but I'm unsure how)
data ??? = 1;
gl.texImage3D(
gl.TEXTURE_3D,
0,
gl.R16I,
size,
size,
size,
0,
gl.RED_INTEGER,
gl.SHORT,
data);
secondly, later in my fragment shader, how could I grab that value using the GLSL texture function. I think it'd go something like this:
uniform isampler3d t_sampler;
...
ivec4 value = texture( t_sampler , vec3( 1.0 , 1.0 , 1.0 ) );
if( value.y == 1 ){
// do some special stuff
}
any help would be appreciated. again I'm just trying to create my texture using a data array I create and then read that value in the frag shader.
fyi this code is running but failing to get to the "do some special stuff" part.
thanks
// ??? (somehow I'd set values of the data array at index 1,1,1 but I'm unsure how)
data ??? = 1;
const width = ??
const height = ??
const depth = ??
const numChannels = 1; // 1 for RED, 2 for RG, 3 for RGB, 4 for RGBA
const sliceSize = width * height * numChannels;
const rowSize = width * numChannels;
const x = 1;
const y = 1;
const z = 1;
const offset = z * sliceSize + y * rowSize + x;
data[offset] = redValue;
If there are more channels, for example RGBA then
data[offset + 0] = redValue;
data[offset + 1] = greenValue;
data[offset + 2] = blueValue;
data[offset + 3] = alphaValue;
how could I grab that value using the GLSL texture function
To get a specific value from a texture you can use texelFetch with pixel/texel coordinates.
uniform isampler3d t_sampler;
...
int x = 1;
int y = 1;
int z = 1;
int mipLevel = 0;
ivec4 value = texelFetch(t_sampler, ivec3(x, y, z), mipLevel);
if( value.y == 1 ){
// do some special stuff
}
Be sure to check the JavaScript console for errors. In your case you probably need to set filtering to NEAREST since you're not providing mips and since integer textures can not be filtered.
When I plot data with ILPlotCube, the (0,0) origin is displayed with some offset (margin/gap) from the x and y axes. How can I remove this offset?
You can use the ILLimits.Set
For example:
var start = -2;
var sz = 6;
ILArray<float> x = Enumerable.Range(start, sz).ToArray();
var pc = new ILPlotCube(twoDMode: true)
{
new ILLinePlot(x)
};
pc.Limits.Set(new Vector3(0, start + sz - 1, 0), new Vector3(sz - 1, start, 0));
Added (01/12/2016)
My understanding was: you want to get rid of the space noted in the red circle?
Get rid of red circle
Also changed the code a bit.
I create an interactive map as follows:
library(leafletR)
data(quakes)
# store data in GeoJSON file (just a subset here)
q.dat <- toGeoJSON(data=quakes[1:99,], dest=tempdir(), name="quakes")
# make style based on quake magnitude
q.style <- styleGrad(prop="mag", breaks=seq(4, 6.5, by=0.5), style.val=rev(heat.colors(5)), leg="Richter Magnitude", fill.alpha=0.7, rad=8)
# create map
q.map <- leaflet(data=q.dat, dest=tempdir(), title="Fiji Earthquakes", base.map="osm", style=q.style, popup="mag")
# view map in browser
rstudio::viewer(q.map)
Now, I want to make the size of the circle dependent on another variable. Let's say the variable 'stations'. How can I do this? If it is not possible with this package, I am open to use another package ... as long as I can put a legend, the map is interactive, a pop-up appear when clicked on and the color can depend on the value of a continuous variable.
I read through the documentation for the leafletR package, and it seems to me (and I could be wrong) that the current version doesn't support multiple styles for the same dataset. They give a few examples where they combine 2 styleSingles by listing them (e.g. style=list(sty.1, sty.2)), but that only works in conjunction with listing 2 different datasets (see P.8 in the document for more details). I tried various tricks, but none of them worked for me.
However, I came up with a hacky solution that you might want to try. After the html page is created using the leaflet() function, you can edit the Javascript code that handles the styling to make the radius property dynamic (this could also work for the other styling properties, such as fill, alpha, etc.).
What you need to know:
In the HTML document that leaflet creates, search for the definition of the style1(feature) function. You should find the following segment of code:
function style1(feature) {
return {"color": getValue(feature.properties.mag),
"fillOpacity": 0.7,
"radius": 8};
}
This function basically returns the style for each record in your dataset. As you can see, the function in its current form returns a static value for fillOpacity and radius. However, when it comes to color, it calls another function called getValue and passes it the mag (magnitude) property. If we take a look at the definition of the getValue function, we'll see that it simply defines the magnitude ranges for each color:
function getValue(x) {
return x >= 6.5 ? "#808080" :
x >= 6 ? "#FF0000" :
x >= 5.5 ? "#FF5500" :
x >= 5 ? "#FFAA00" :
x >= 4.5 ? "#FFFF00" :
x >= 4 ? "#FFFF80" :
"#808080";
}
The function definition is really simple. If x (the magnitude in this case) is greater or equal to 6.5, then the color of that data point will be "#808080". If it's between 6 and 6.5, then the color will be #FF0000". And so on and so forth.
What you can do:
Now that we see how the Javascript code handles how the colors are assigned to each data point, we can do something similar for all the other styling properties with very minimal effort. The following code segment, for instance, shows how you can make the radius dynamic based on the count of stations in the area:
/* The getValue function controls the color of the data points */
function getValue(x) {
return x >= 6.5 ? "#808080" :
x >= 6 ? "#FF0000" :
x >= 5.5 ? "#FF5500" :
x >= 5 ? "#FFAA00" :
x >= 4.5 ? "#FFFF00" :
x >= 4 ? "#FFFF80" :
"#808080";
}
/* The getRadValue function controls the radius of the data points */
function getRadValue(x) {
return x >= 100 ? 24 :
x >= 80 ? 20 :
x >= 60 ? 16 :
x >= 40 ? 12 :
8;
}
/* The updated definition of the style1 function */
function style1(feature) {
return {"color": getValue(feature.properties.mag),
"fillOpacity": 0.7,
"radius": getRadValue(feature.properties.stations)
};
}
So, with the new definition of style1(feature), now we can control both the color as well as the radius of the data points. The result of the code modification looks like this:
The good thing about this approach is that it gives you more fine-grained control over the styling properties and the range of values that they can have. The major draw-back is going to be that if you want to add a legend for those properties, then you'll have to do that manually. The logic for adding/editing the legend should be at the very bottom of the HTML document, and if you know Javascript/HTML/CSS, editing that code segment shouldn't be too difficult.
Update:
To add a legend for the new dynamic variable (in our case, the radius), you need to edit the .onAdd handler that's attached to the legend object. As I said before, the definition for this handler is usually at the bottom of the html page, and if we run the bit of code that you provided in your question, then the handler should look like this:
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'legend');
var labels = [];
var grades = [4, 4.5, 5, 5.5, 6, 6.5];
div.innerHTML += 'Richter Magnitude<br>';
for (var i = 0; i < grades.length - 1; i++) {
div.innerHTML += '<i style="background:' + getValue(grades[i]) + '"></i> ' + grades[i] + '–' + grades[i + 1] + '<br>';
}
return div;
};
The above code simply loops through the range of values for the magnitude, and creates a box (with the appropriate color, referencing the getValue function that we looked at before) and a label. If you want to create something similar for the stations variable, let's say, we can use the same logic above. Though in this case instead of varying the color, we'll be varying the size of the circle. The following segment of code shows how to achieve that:
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'legend');
var labels = [];
var grades = [4, 4.5, 5, 5.5, 6, 6.5];
div.innerHTML += 'Richter Magnitude<br>';
for (var i = 0; i < grades.length - 1; i++) {
div.innerHTML += '<i style="background:' + getValue(grades[i]) + '"></i> ' + grades[i] + '–' + grades[i + 1] + '<br>';
}
// Adding the range of possible of values that the variable might take
// This should be in sync with the range of values you considered in
// the getRadValue function.
var rad_grades = [40, 60, 80, 100];
// The title for this section of the legend
div.innerHTML += 'Number of stations<br>'
for (var i = 0; i < rad_grades.length - 1; i++) {
div.innerHTML += '<table style="border: none;"><tr><td class="circle" style="width: ' +
(getRadValue(rad_grades[rad_grades.length - 2]) * 2 + 6) + 'px;"><svg style="width: ' +
(getRadValue(rad_grades[i]) * 2 + 6) + 'px; height: ' + (getRadValue(rad_grades[i]) * 2 + 6) +
'px;" xmlns="http://www.w3.org/2000/svg" version="1.1"><circle cx="' + (getRadValue(rad_grades[i]) + 3) + '" cy="' +
(getRadValue(rad_grades[i]) + 3) + '" r="' + getRadValue(rad_grades[i]) + '" /></svg></td><td class="value">' +
rad_grades[i] + '–' + rad_grades[i + 1] + '</td></tr></table>';
}
return div;
};
As you can see, the type of styling property we're controlling will determine how we're specifying it in the legend. If you want to add a legend for the alpha property, for instance, then you might want to try some other approach other than using circles and controlling their width and height. The end result of the code modifications above looks like this:
Also, if you want to include the number of stations in the popup, then you'll have to edit the onEachFeature function. It's going to be the same approach we took with all the other modifications, and it's a really simple change.
The onEachFeature function looks like this in the original HTML:
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.mag) {
layer.bindPopup("mag: " + feature.properties.mag);
}
}
If you want to include the number of stations in the popup too, then you need to include it in the argument to the bindPopup method, as follows:
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.mag && feature.properties.stations) {
layer.bindPopup("mag: " + feature.properties.mag + "<br> # Stations: " + feature.properties.stations);
}
}
The end result of this change is the following:
Hope this helps.
In this answer to my recent question, there is some code that draws a graph, but I can't manage to edit it into something that accepts any list of points as a parameter.
I'd like the Drawing method to accept these parameters:
List of Vector2, Point or VertexPositionColor, I can work with whichever.
Offset for the whole graph
These optional requirements would be appreciated:
Color that may override VertexPositionColor's color and apply to all points.
Size of the graph, so it can be shrunk or expanded, either as Vector2 as multiplier, or Point as target size. Maybe even combine this with offset in Rectangle.
And if it's possible, I'd like to have it all in a class, so graphs can be used separately from each other, each with its own Effect.world matrix, etc.
Here is that code (by Niko Drašković):
Matrix worldMatrix;
Matrix viewMatrix;
Matrix projectionMatrix;
BasicEffect basicEffect;
VertexPositionColor[] pointList;
short[] lineListIndices;
protected override void Initialize()
{
int n = 300;
//GeneratePoints generates a random graph, implementation irrelevant
pointList = new VertexPositionColor[n];
for (int i = 0; i < n; i++)
pointList[i] = new VertexPositionColor() { Position = new Vector3(i, (float)(Math.Sin((i / 15.0)) * height / 2.0 + height / 2.0 + minY), 0), Color = Color.Blue };
//links the points into a list
lineListIndices = new short[(n * 2) - 2];
for (int i = 0; i < n - 1; i++)
{
lineListIndices[i * 2] = (short)(i);
lineListIndices[(i * 2) + 1] = (short)(i + 1);
}
worldMatrix = Matrix.Identity;
viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up);
projectionMatrix = Matrix.CreateOrthographicOffCenter(0, (float)GraphicsDevice.Viewport.Width, (float)GraphicsDevice.Viewport.Height, 0, 1.0f, 1000.0f);
basicEffect = new BasicEffect(graphics.GraphicsDevice);
basicEffect.World = worldMatrix;
basicEffect.View = viewMatrix;
basicEffect.Projection = projectionMatrix;
basicEffect.VertexColorEnabled = true; //important for color
base.Initialize();
}
And the drawing method:
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
PrimitiveType.LineList,
pointList,
0,
pointList.Length,
lineListIndices,
0,
pointList.Length - 1
);
}
The Graph class that does the requested can be found here.About 200 lines of code seemed too much to paste here.
The Graph is drawn by passing a list of floats (optionally with colors) to its Draw(..) method.
Graph properties are:
Vector2 Position - the bottom left corner of the graph
Point Size - the width (.X) and height (.Y) of the graph. Horizontally, values will be distributed to exactly fit the width. Vertically, all values will be scaled with Size.Y / MaxValue.
float MaxValue - the value which will be at the top of the graph. All off the chart values (greater than MaxValue) will be set to this value.
GraphType Type - with possible values GraphType.Line and GraphType.Fill, determines if the graph will be drawn line only, or bottom filled.
The graph is drawn with a line list / triangle strip.