jFreeChart LineChart adjust Ticks - jfreechart

I'm sure the answer is here somewhere but I really can't find it.
I have a LineChart with a lot of entries (lets say 1000). In the plot I can see (and adjust (see A)) the Y-axis perfectly well. Just the X-axis drives me nuts!
With 1000 entries there is no number of the bottom of the plot.
A:
With this I can adjust the Y-axis nicely.
final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setRange(0.00, 1.00);
rangeAxis.setTickUnit(new NumberTickUnit(0.2));
rangeAxis.setVerticalTickLabels(false);
I wanna do the same with the X-axis.
Please help me out.
Thanks a lot
-> problem with first answer | Domain axis with 100 numbers and an interval of 50

I am afraid you have to modified the code of JfreeChart, Is Opensource great?
I have this problem before for my BarChart, What I did is to customize the tick on x-Axis
I only implemented this for CategoryAxis.java alone. I hope this can shed some light on you.
Please note the variable "tickInterval", I added this property to the class,
for example you have 1000 numbers, if set tickInterval as 99, only
0, 100, 200, 300 ... will show up.
bye the way, my freechart version is 1.0.5
public List refreshTicks(Graphics2D g2,
AxisState state,
Rectangle2D dataArea,
RectangleEdge edge) {
List ticks = new java.util.ArrayList();
// sanity check for data area...
if (dataArea.getHeight() <= 0.0 || dataArea.getWidth() < 0.0) {
return ticks;
}
CategoryPlot plot = (CategoryPlot) getPlot();
List categories = plot.getCategoriesForAxis(this);
double max = 0.0;
if (categories != null) {
CategoryLabelPosition position
= this.categoryLabelPositions.getLabelPosition(edge);
float r = this.maximumCategoryLabelWidthRatio;
if (r <= 0.0) {
r = position.getWidthRatio();
}
float l = 0.0f;
if (position.getWidthType() == CategoryLabelWidthType.CATEGORY) {
l = (float) calculateCategorySize(categories.size(), dataArea,
edge);
}
else {
if (RectangleEdge.isLeftOrRight(edge)) {
l = (float) dataArea.getWidth();
}
else {
l = (float) dataArea.getHeight();
}
}
int categoryIndex = 0;
Iterator iterator = categories.iterator();
while (iterator.hasNext()) {
Comparable category = (Comparable) iterator.next();
if(categoryIndex>0 && tickInterval>0)
{
if((categoryIndex+1) % (tickInterval+1) > 0)
{
category = "";
}
}
TextBlock label = null;
if(tickInterval> 0)
{
label = this.createSingleLabel(category, l * r, edge, g2);
}
else
{
label = createLabel(category, l * r, edge, g2);
}
if (edge == RectangleEdge.TOP || edge == RectangleEdge.BOTTOM) {
max = Math.max(max, calculateTextBlockHeight(label,
position, g2));
}
else if (edge == RectangleEdge.LEFT
|| edge == RectangleEdge.RIGHT) {
max = Math.max(max, calculateTextBlockWidth(label,
position, g2));
}
Tick tick = new CategoryTick(category, label,
position.getLabelAnchor(), position.getRotationAnchor(),
position.getAngle());
ticks.add(tick);
categoryIndex = categoryIndex + 1;
}
}
state.setMax(max);
return ticks;
}

Related

How can i stop the rotation of an object in an array? P5.JS

this is for a project in my p5.js class.
I have a class that creates a 3D shape and i call it in my draw function in a for loop. In this for loop i create the shape and it has a rotation. If i press the the "a" button, it creates a new shape. My problem is, that i want to stop the rotation of the previous shape when i create a new shape, but i can't find a solution.
this is my code:
let BLACK;
let GRAY;
let LIGHTGRAY;
let WHITE;
let RED;
let forms = [];
let coorX, coorY, coorZ, colour;
let COL = [];
let ran;
function setup() {
createCanvas(586, 810, WEBGL);
BLACK = color(0);
GRAY = color(70);
LIGHTGRAY = color(180);
WHITE = color(255);
RED = color(217, 4, 33);
COL = [BLACK, WHITE, GRAY, RED, RED\]
ran = random(0.01, 0.1)
}
function draw() {
background(80);
pointLight(250, 250, 250, 250);
for (let i = 0; i < forms.length; i++) {
newSpeed = 0.05 + i * ran
forms[i].create(newSpeed, 0.01);
if (forms.length > 1) {
rotateX(0);
}
}
if (forms.length > 10) {
//Array limited on 10 objects
forms.splice(0, 1)
}
}
function keyTyped() {
if (key === 'a') {
coorX = int(random(-100, 100))
coorY = int(random(-100, 100))
coorZ = int(random(-200, 200))
forms.push(new Shape(coorX, coorY, coorZ));
}
if (key === 'd') {
forms.pop()
}
}
class Shape {
constructor(posX, posY, posZ, colour) {
this.x = 50; //width
this.y = 50; //height
this.z = 50; // depth
this.x1 = 0;
this.y1 = 500;
this.z1 = 80;
this.posX = posX;
this.posY = posY;
this.posZ = posZ;
this.rand = int(random(0, 5));
this.colour = colour;
}
create (speed, rotation) {
//create a new shape
stroke(0);
strokeWeight(0);
push();
translate(this.posX, this.posY, this.posZ)
//rotate the shape
this.speed = speed;
this.rotation = rotation;
rotateX((frameCount * this.rotation) * speed)
rotateY((frameCount * this.rotation) * speed)
if (this.rand == 1) {
fill(RED)
box(50, 50, 50)
}
if (this.rand == 2) {
fill(LIGHTGRAY);
sphere(50, 10)
}
if (this.rand == 3) {
fill(WHITE);
cylinder(5, 280, 15)
}
if (this.rand == 4) {
fill(GRAY);
torus(90, 24, 3)
}
pop();
}
}
I tried separating the rotation and the creation function, but then it rotated the whole canvas and not the shapes individually.
In fact, in p5.js approach is completely different, and You need to analyze this example: https://p5js.org/examples/simulate-multiple-particle-systems.html
But, to solve Your problem in 'object style':
1 - You need to memorize state of the object, in this case the frameCount of the last frame when the key a was pressed,
2 - draw all shapes with memorized lastActiveFrame and one just with recent frameCount.
let BLACK;
let GRAY;
let LIGHTGRAY;
let WHITE;
let RED;
let forms = [];
let coorX, coorY, coorZ, colour;
let COL = [];
let ran;
function setup() {
createCanvas(586, 810, WEBGL);
BLACK = color(0);
GRAY = color(70);
LIGHTGRAY = color(180);
WHITE = color(255);
RED = color(217,4,33);
COL = [BLACK, WHITE, GRAY, RED, RED]
ran = random(0.01,0.1)
coorX = int(random(-100,100))
coorY = int(random(-100,100))
coorZ = int(random(-200,200))
forms.push(new Shape(coorX, coorY, coorZ));
}
function draw() {
background(80);
pointLight(250, 250, 250, 250);
for(let i = 0; i < forms.length-1; i++) {
newSpeed = 0.05 + i * ran
forms[i].show(newSpeed, 0.01);
}
forms[forms.length-1].rotate(2.5, 0.01);
if (forms.length > 10){
//Array limited on 10 objects
forms.splice(0,1)
}
}
function keyTyped() {
if (key === 'a'){
coorX = int(random(-100,100))
coorY = int(random(-100,100))
coorZ = int(random(-200,200))
forms.push(new Shape(coorX, coorY, coorZ));
}
if (key === 'd'){
forms.pop()
}
}
class Shape {
constructor(posX, posY, posZ, colour){
this.posX = posX;
this.posY = posY;
this.posZ = posZ;
this.rand = int(random(0,5));
this.colour = colour;
this.lastActiveFrame = frameCount;
}
rotate(speed, rotation){
//create a new shape
stroke(0);
strokeWeight(0);
push();
translate(this.posX, this.posY, this.posZ)
//rotate the shape
this.lastActiveFrame = frameCount;
rotateX(frameCount * rotation * speed)
rotateY(frameCount * rotation * speed)
if (this.rand == 1){
fill(RED)
box(50,50,50)
}if(this.rand == 2) {
fill(LIGHTGRAY);
sphere(50,10)
}if(this.rand == 3){
fill(WHITE);
cylinder(5,280,15)
}if(this.rand == 4){
fill(GRAY);
torus(90,24,3)
}
pop();
}
show(speed, rotation){
//create a new shape
stroke(0);
strokeWeight(0);
push();
translate(this.posX, this.posY, this.posZ)
//rotate the shape
rotateX(this.lastActiveFrame * rotation * speed)
rotateY(this.lastActiveFrame * rotation * speed)
if (this.rand == 1){
fill(RED)
box(50,50,50)
}if(this.rand == 2) {
fill(LIGHTGRAY);
sphere(50,10)
}if(this.rand == 3){
fill(WHITE);
cylinder(5,280,15)
}if(this.rand == 4){
fill(GRAY);
torus(90,24,3)
}
pop();
}
}
In the console, p5.js says that the 4th argument of pointLight() must be a Vector. That argument is used to tell in which direction the light will point, as for the arguments 1 - 3, they tell where is the pointLight.
Vector reference
pointLight reference

Scrolling through an array

So I have a project in GameMaker, which has a chatbox. The messages for this are stored in an array. I would like to be able to scroll through this array, so I can view earlier chat messages.
This is what I currently have:
Create Event
chatLog[0] = "";
chatIndex = 0;
Step Event
if (chatIndex > 0) {
if (mouse_wheel_down()) {
chatIndex--;
}
}
if (chatIndex < array_length_1d(chatLog) - 1) {
if (mouse_wheel_up()) {
chatIndex++;
}
}
var _maxLines = 5;
for (i = 0; i < _maxLines; i++) {
if (i > (array_length_1d(chatLog) - 1)) { exit; }
var _chatLength = array_length_1d(chatLog) - 1;
draw_text(0, 50 - chatHeight, chatLog[_chatLength - i + chatIndex]);
}
First, for convenience of being able to add messages to front / remove them from the back (once there are too many), let's suppose that the log is a list, item 0 being the newest message,
chatLog = ds_list_create();
chatIndex = 0;
for (var i = 1; i <= 15; i++) {
ds_list_insert(chatLog, 0, "message " + string(i));
}
then, the Step Draw event can use information from the list to clamp scroll offset range and draw items:
var maxLines = 5;
// scrolling:
var dz = (mouse_wheel_up() - mouse_wheel_down()) * 3;
if (dz != 0) {
chatIndex = clamp(chatIndex + dz, 0, ds_list_size(chatLog) - maxLines);
}
// drawing:
var i = chatIndex;
var _x = 40;
var _y = 200;
repeat (maxLines) {
var m = chatLog[|i++];
if (m == undefined) break; // reached the end of the list
draw_text(_x, _y, m);
_y -= string_height(m); // draw the next item above the current one
}
live demo

Check transformation values before applying the transform

I'm using a render transform to pan an image. I need the panning to stop at a certain point, so I'm checking the bounds of the image. The problem is that the image can be panned slightly beyond the bounds, because I'm checking the bounding box before the transform has been applied. Is there a way of applying the transform to the bounding box, then checking if this is within the valid range?
Thanks for any help
private void RecalculatePositions(MouseEventArgs e)
{
TranslateTransform tt1 = (TranslateTransform)((TransformGroup)this.image1.RenderTransform).Children.First(tr => tr is TranslateTransform);
TranslateTransform tt2 = (TranslateTransform)((TransformGroup)this.image2.RenderTransform).Children.First(tr => tr is TranslateTransform);
Vector vector = this._startPoint - e.GetPosition(this.grid);
double offsetX = this._originPoint.X - vector.X;
double offsetY = this._originPoint.Y - vector.Y;
Rect image1Bounds = this.image1.TransformToAncestor(this.viewBox1).TransformBounds(new Rect(this.image1.RenderSize));
if (vector.X < 0)
{
//Moving image right
if (offsetX <= 0)
{
tt1.X = offsetX;
tt2.X = offsetX;
}
}
else
{
//Moving image left
if (image1Bounds.Right >= 0)
{
tt1.X = offsetX;
tt2.X = offsetX;
}
}
if (vector.Y < 0)
{
//Moving image down
if (offsetY <= 0)
{
tt1.Y = offsetY;
tt2.Y = offsetY;
}
}
else
{
//Moving image up
if (image1Bounds.Bottom >= this.ActualHeight)
{
tt1.Y = offsetY;
tt2.Y = offsetY;
}
}
}

D3 import .csv to 2Darray & opacity change when hover

I'm currently writing a visualization via D3 and I hope you can help me out.
To get an idea of what I'm making you can view this link: https://dl.dropboxusercontent.com/u/56480311/Data-visualization/index.html
I'm facing two problems: the first is that I can't seem to place .csv data in a 2D array. I found multiplie tutorials about placing it in a normal array but the only solution I came up with if your data is in a table, is to use a 2D array. I couldn't find how to do this so what I thought would help:
var lines = []; //define lines as an array
//retrieve data from .csv file
d3.csv("https://dl.dropboxusercontent.com/u/56480311/Data-visualization/growth-prep.csv", function(data) {
lines = data.map(function(d) {
return d;
});
});
//create 2D array named myArray
var myArray = new Array(10);
for (var i = 0; i < 10; i++) {
myArray[i] = new Array(18);
}
//place each value of .csv file into myArray
for (var j = 0; j < lines.length; j++) {
var values = lines[j].split(";");
for (var k = 0; k < values.length; k++) {
myArray[k][j] = values[k];
}
}
This code doesn't work, however. Console keeps saying that the arrays are undefined and they're empty.
A second problem I'm facing is in visualizing the data. I sum three values that are next to each other (so for example dataset[0][0] + dataset[0][1] + dataset[0][2]). I draw this value as the width of a rectangle. On top of that, I want to draw three different rectangles each with the value of one of three. So in this case there is one rectangle consisting of dataset[0][0] + dataset[0][1] + dataset[0][2] and on top there is a rectangle showing data dataset[0][0], one showing data dataset[0][1] and a third showing data dataset[0][2]. I want the three smaller ones only to appear once the mouse hovers over the 'sum' / parent rectangle.
If you view the link you can see what I mean. Everything is already there, only the three smaller rectangles have opacity 0 so you don't see them yet (but you can find them via inspect elements).
I figured I could do this by setting the opacity of the three rectangles to 0 and to 1 once the mouse hovers. The best solution to me would be to place the three rectangles into one kind of div. Once the mouse hovers over it, its opacity is 1. Only I can't figure out how to easily give different class names without having to do it by hand for each rectangle separately. Does anyone know how to do this or else have a better solution to change the opacity of all three rectangles once the mouse hovers over the 'bigger' rectangle?
This is the code:
var dataset = [[6,6,3,3,3,0,6,6,0,12,6,6,0,0,18,6,3,3],[3,0,0,6,3,0,3,3,0,9,3,0,0,0,18,6,6,6],[3,0,3,6,3,3,6,0,3,9,6,3,0,0,15,6,6,6],[6,6,3,3,0,3,6,6,6,12,6,6,0,0,18,6,6,3],[6,6,0,6,0,0,6,6,6,12,6,6,0,0,24,6,6,0],[3,6,3,6,3,3,6,6,3,3,0,0,0,0,15,3,9,6],[3,3,0,3,0,3,3,3,3,9,3,0,0,0,15,6,3,9],[0,0,0,3,0,6,6,3,3,3,0,3,0,0,24,6,12,6],[6,6,3,6,0,0,9,9,6,12,6,6,0,0,15,3,3,3],[6,6,0,6,3,0,6,6,0,9,6,3,0,0,9,3,6,0]];
var h = 800;
var w = 800;
//create svg of 800x800px
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xPos = 150;
for (var k = 0; k < 10; k++) { //loop through lines of array
var yPos = 40 + k*80;
for (var j = 0; j < 18; j++) { //loop through rows of array
var count = j + 1;
//assign data of three boxes to value1/value2/value3 with which we will later on draw three separate rectangles to visualize the data
if (count == 1 || count == 4 || count == 7 || count == 10 || count == 13 || count == 16) {
var value1 = dataset[k][j];
}
if (count == 2 || count == 5 || count == 8 || count == 11 || count == 14 || count == 17) {
var value2 = dataset[k][j];
}
if (count == 3 || count == 6 || count == 9 || count == 12 || count == 15 || count == 18) {
var value3 = dataset[k][j];
}
if (count % 3 ==0) {
var sum = dataset[k][j] + dataset[k][j-1] + dataset[k][j-2]; //count the three values to also draw one bigger rectangle of their sum
var rectangle = svg.append("rect")
.attr("x", xPos)
.attr("y", yPos)
.attr("width", sum*5)
.attr("height", 20)
.attr("fill", function(d) {
if (count == 3) {
return "LightSeaGreen";
}
else if (count == 6) {
return "MediumSeaGreen";
}
else if (count == 9) {
return "MediumSpringGreen";
}
else if (count == 12) {
return "LimeGreen";
}
else if (count == 15) {
return "ForestGreen"
}
else if (count == 18) {
return "GreenYellow"
}
});
for (var l = 0; l < 3; l++) { //draw three 'sub' rectangles on top of the one 'sum' rectangle. they should appear when the mouse hovers over their 'sum' rectangle
var rectangle2 = svg.append("rect")
.attr("class", "sqr")
.attr("x", function() {
if (l == 0) {
return xPos;
} else if (l == 1) {
return xPos + value1*5;
} else if (l == 2) {
return xPos + (value1+value2)*5;
}
})
.attr("y", yPos)
.attr("width", function() {
if (l == 0) {
return value1*5;
} else if (l == 1) {
return value2*5;
} else if (l == 2) {
return value3*5;
}
})
.attr("height", 20)
.attr("fill", function() {
if (l == 0) {
return "SteelBlue";
} else if (l == 1) {
return "aquamarine";
} else if (l == 2) {
return "SkyBlue";
}
})
.attr("opacity", 0); //in first instance the rectangles are not visible. Opacity should turn to 1 when the mouse hovers over their according div
}
if (sum > 0) {
xPos = xPos + sum*5 + 5;
}
}
}
xPos = 150;
}

Box2d elastic rope joint

I'm writing a game, and I need to make up a rope. I maked it by b2RopeJoint, but there I have not found an opportunity to make it elastic.
Then I looked for b2DistanceJoint, everything is cool with the elasticity, but I can't find an ability to set a limit only to the maximum distance (without minimum one).
How can I do it?
Try this.
-(void) CreateElasticRope {
//=======Params
// Position and size
b2Vec2 lastPos = b2Vec2(4,4); //set position first body
float widthBody = 0.35;
float heightBody = 0.1;
// Body params
float density = 0.05;
float restitution = 0.5;
float friction = 0.5;
// Distance joint
float dampingRatio = 0.0;
float frequencyHz = 0;
// Rope joint
float kMaxWidth = 1.1;
// Bodies
int countBodyInChain = 15;
b2Body* prevBody;
//========Create bodies and joints
for (int k = 0; k < countBodyInChain; k++) {
b2BodyDef bodyDef;
if(k==0 ) bodyDef.type = b2_staticBody; //first body is static
else bodyDef.type = b2_dynamicBody;
bodyDef.position = lastPos;
lastPos += b2Vec2(2*widthBody, 0); //modify b2Vect for next body
bodyDef.fixedRotation = YES;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape distBodyBox;
distBodyBox.SetAsBox(widthBody, heightBody);
b2FixtureDef fixDef;
fixDef.density = density;
fixDef.restitution = restitution;
fixDef.friction = friction;
fixDef.shape = &distBodyBox;
body->CreateFixture(&fixDef);
body->SetHealth(9999999);
body->SetLinearDamping(0.0005f);
if(k>0) {
//Create distance joint
b2DistanceJointDef distJDef;
b2Vec2 anchor1 = prevBody->GetWorldCenter();
b2Vec2 anchor2 = body->GetWorldCenter();
distJDef.Initialize(prevBody, body, anchor1, anchor2);
distJDef.collideConnected = false;
distJDef.dampingRatio = dampingRatio;
distJDef.frequencyHz = frequencyHz;
world->CreateJoint(&distJDef);
//Create rope joint
b2RopeJointDef rDef;
rDef.maxLength = (body->GetPosition() - prevBody->GetPosition()).Length() * kMaxWidth;
rDef.localAnchorA = rDef.localAnchorB = b2Vec2_zero;
rDef.bodyA = prevBody;
rDef.bodyB = body;
world->CreateJoint(&rDef);
} //if k>0
prevBody = body;
} //for
}
There's a 2.2 style ropejoint implementation here: https://github.com/aaronfarr/box2Dweb
You can use both a rope joint and a distance joint together. Make the distance of the rope joint a bit longer than the distance joint.
From the Box2D testbed example, I modified the "Web" example as follows:
#ifndef ELASTICROPE_H
#define ELASTICROPE_H
#define NUM_JOINTS 7
#define NUM_LINKS 8
class ElasticRope : public Test
{
public:
ElasticRope()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2CircleShape shape;
shape.m_radius = 0.8f;
// create bodies
for (int b = 0; b < NUM_LINKS; b++) {
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(5.0f, NUM_LINKS-b);
m_bodies[b] = m_world->CreateBody(&bd);
m_bodies[b]->CreateFixture(&shape, 5.0f);
}
for (int j = 0; j < NUM_JOINTS; j++) {
b2DistanceJointDef jd;
b2Vec2 p1, p2, d;
jd.frequencyHz = 5.0f;
jd.dampingRatio = 1.0f;
jd.bodyA = m_bodies[j];
jd.bodyB = m_bodies[j+1];
m_joints[j] = m_world->CreateJoint(&jd);
}
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "This demonstrates an elastic rope.");
m_textLine += DRAW_STRING_NEW_LINE;
}
void JointDestroyed(b2Joint* joint)
{
for (int32 i = 0; i < 8; ++i)
{
if (m_joints[i] == joint)
{
m_joints[i] = NULL;
break;
}
}
}
static Test* Create()
{
return new ElasticRope;
}
b2Body* m_bodies[NUM_LINKS];
b2Joint* m_joints[NUM_JOINTS];
};
#endif // ELASTICROPE_H
Its far from perfect, but may be a starting point.

Resources