user3450277
user3450277

Reputation: 436

JAVA: Confusion with correct for-loop iteration?

Background Information:

I am writing a program where I am supposed to graph a data set, which is stored in the following file (input file), called "names.txt", using the class DrawingPanel.

This java file allows you to create a panel of a given size, and draw shapes and lines in this panel. The problems I am encountering with my program are unrelated to the specifications and understandings of the class methods.

The data set that I am supposed to graph using this java file is configured in the following way:

[name] [gender] [ranking] [ranking] [ranking] [ranking]....etc for a total of 14 rankings.

Example:

Jane F 98 108 128 116 48 55 47 39 67 202 312 345 436 384

General goal of program: The user is supposed to input the name and gender they would like to see graphed. The data is then graphed, rankings representing the y axis and time representing the x axis.

My main problem is drawing the lines that compose the graph. The lines of these graphs are drawn with the method:

g.drawLine(x1, y1, x2, y2)

with g representing a Graphics object. Two points are necessary as two endpoints are necessary to create a line.

This for loop is responsible for printing the lines.

    for (int j = 0; j < SECTION_WIDTH * DECADES; j += SECTION_WIDTH){
            g.setColor(Color.BLACK);
            g.drawLine(j, yCoordinate, i + intervalIncrease, yCoordinate2);
            g.setColor(Color.RED);
            intervalIncrease += SECTION_WIDTH;
            g.drawString(intervalLabel, intervalIncrease , yCoordinate);
            }            
    }

SUMMARY OF PROBLEM: The for loop above is the cause of the bugs in my program. The problem is the incorrect printing of the lines that compose the graph. This is caused by incorrect for loop iterations and conditions, which are complicated by the awkward location of the for loop and the fact that two calls of everything are necessary to correctly run the program. Despite guessing-and-checking for several hours, I cannot figure out how to manipulate the loops to make it work.

It is complicated because the drawString method is dependent on the drawLine method variables.

I've tried implementing this into my code but it hasn't worked.

Specific Requirements and Additional Information on DrawingPanel.java:

Please see this (Specification) for specifications on what the graph should look like and other requirements.

An image of what the graph should look like is also provided below.

    public static void drawRanks(String line, Graphics g){
    int yearIncrease = 0;
    int intervalIncrease = 0;
    System.out.println(line);
    Scanner lineScan = new Scanner(line);
    String name = lineScan.next();
    String gender = lineScan.next();
    for(int i = 0; i < DECADES/2; i++) {
        g.setColor(Color.RED);
        int rank = lineScan.nextInt();
        int rank2 = lineScan.nextInt();
        int yCoordinate = rank/2 + 25;
        int yCoordinate2 = rank2/2 + 25;
        String intervalLabel = name + " " + gender + " " + String.valueOf(rank);
        String intervalLabel2 = name + " " + gender + " " + String.valueOf(rank2);
        if (rank == 0){
            yCoordinate = 525;
        }
        if (rank2 == 0){
            yCoordinate2 = 525;
        }
        for (int j = 0; j < SECTION_WIDTH * DECADES; j += SECTION_WIDTH){
            g.setColor(Color.BLACK);
            g.drawLine(j, yCoordinate, i + intervalIncrease, yCoordinate2);
            g.setColor(Color.RED);
            intervalIncrease += SECTION_WIDTH;
            g.drawString(intervalLabel, intervalIncrease , yCoordinate);
            }            
    }

    for(int j = 0; j < DECADES; j++) {
        g.setColor(Color.BLACK);
        g.drawString(String.valueOf(STARTING_YEAR + yearIncrease), SECTION_WIDTH * j, 550);
        yearIncrease += 10;
    }  

    for (int k = DECADES * SECTION_WIDTH; k >= 0; k -= SECTION_WIDTH){
        g.drawLine(k, 0, k, 550);
    }

}

Image of graph produced: DrawingPanel Graph

Expected graph: Expected DrawingPanel Graph

Please feel free to comment if my explanation is unclear. Here is where the DrawingPanel class is located, for compilation purposes, if necessary. DrawingPanel.java

Here is an API for the methods:

DrawingPanel name = new DrawingPanel(width, height);

Graphics g - name.getGraphics();

panel.setBackground(color); -  sets panel's background color

g.setColor(color); - sets Graphics pen color (like dipping a brush in paint)

g.drawLine(x1, y2, x2, y2); - a line from points (x1, y1) to (x2, y2)

g.drawString(text, x, y); - the given text with its lower-left corner at (x, y)

Upvotes: 0

Views: 197

Answers (1)

RealSkeptic
RealSkeptic

Reputation: 34628

Your general idea, that you have to read the ranks in pairs, is wrong. What you have to do is draw a line from the last rank's coordinates to the current rank's coordinates. Here is my version of your method (mind you, I don't have your whole environment so I can't actually test this):

public static void drawRanks(String line, Graphics g){
    int yearIncrease = 0;
    System.out.println(line);
    Scanner lineScan = new Scanner(line);
    String name = lineScan.next();
    String gender = lineScan.next();
    int lastRank = lineScan.nextInt();
    int lastY = lastRank/2 + 25;
    if ( lastRank == 0 ) {
        lastY = 525;
    }
    int lastX = 0;

    while ( lineScan.hasNextInt() ) {
        int rank = lineScan.nextInt();

        int y = rank/2 + 25;
        if (rank == 0){
            y = 525;
        }
        int x = lastX + SECTION_WIDTH;

        String intervalLabel = name + " " + gender + " " + String.valueOf(lastRank);

        g.setColor(Color.RED);
        g.drawLine(lastX, lastY, x, y);
        g.drawString(intervalLabel,lastX,lastY);
        lastX = x;
        lastY = y;
        lastRank = rank;

    }

    g.drawString(intervalLabel,lastX,lastY);

    for(int j = 0; j < DECADES; j++) {
        g.setColor(Color.BLACK);
        g.drawString(String.valueOf(STARTING_YEAR + yearIncrease), SECTION_WIDTH * j, 550);
        yearIncrease += 10;
    }  

    for (int k = DECADES * SECTION_WIDTH; k >= 0; k -= SECTION_WIDTH){
        g.drawLine(k, 0, k, 550);
    }

}

So at first you read the name and gender, and then you read the first rank, to give you initial coordinates.

Then, in every iteration of the loop, you read just one rank. You draw the line from your previous rank to your new rank. You draw the label that belongs to the previous rank at the previous rank's coordinates. And then you save your current x,y and rank to the lastX, lastY and lastRank respectively, so that you can rely on them in the next iteration.

After the loop is done, you still have one label you haven't drawn so you draw that, and then you go on to draw the black lines (I haven't looked into the correctess of your code there, just left it as is).

Upvotes: 2

Related Questions