Silverthorn - 3 months ago 35

Python Question

I want to do a plot in Python3 that will show me the assignments on the x-axis and the grades on the y-axis. The x-axis must show all assignments from 1 to M, and the y-axis must show all grades 3 to 12.

Input is a matrix of grades for M assignments: e.g. for 6 Assignments I have the following input:

`array([[10, -3, 10, ..., 7, 0, 12],`

[12, 12, 12, ..., 10, 0, 12],

[7, 7, 10, ..., 10, 0, 10],

[7, 4, 7, ..., 7, 0, 12],

[-3, 4, 7, ..., 4, 4, 12],

[7, 4, 4, ..., 4, 0, 12]], dtype=object)

- First row - assignment 1 grades
- Second row - assignment 2 grades
- etc.

The plot must also contain:

- Each of the given grades marked by a dot. I need to add a small random

number (between -0.1 and 0.1) to the x- and y-coordinates of each dot, to

be able tell apart the different dots which otherwise would be on top of each

other when more than one student has received the same grade in the same

assignment. - The average grade of each of the assignments plotted as a line.

I have started by trying with a for loop to plot each assignment, but it does not seem to work - therefore I am stuck at the moment.

`import matplotlib.pyplot as plt`

yaxis = np.arange(-3, 13)

for i in range(len(assignments)-1):

plt.plot(assignments[i, :], yaxis, label = "Assignemnt [i]")

plt.title("Grades per assignment")

plt.xlabel("Assignments")

plt.ylabel("Grades")

plt.show()

Answer

If I understood your question, this is what you want? Not sure how you want the average grade to be represented, but I left it as an exercise for you.

**EDIT**

For each call of `plot()`

you have to have an `x`

array and a `y`

array that are the same dimensions. Here, I iterate over the data array, one row at a time using `enumerate()`

, which returns an index, which I called `a`

, and the row, which I called `grades`

. There are 6 rows, so `a`

will successively take the values 0,1,2,3,4,5,6.

Then, since you want to plot each grade against the assignment number `a`

, you'd be tempted to do `plot(a, grades)`

. But, since `x`

and `y`

need to have the same dimension, we need to generate an array that has the same dimension as `grades`

, which is what `x = a*np.ones(len(grades))`

does. From there, you could do `plot(x, grades)`

. But then, equal grades would overlap, as you pointed out in your question.

To avoid the overlap, I add a random number between `[-0.1, 0.1)`

using the formula `(jitter_max-jitter_min)*np.random.random(size=len(grades))+jitter_min`

(see the documentation for `np.random.random()`

).

To plot the average, you simply need to calculate the average row-by-row, store that value in an array, then plot that array against an array of same dimension containing the assignment number (0,1,2,3,...). To plot it as a line, instead of simply points, check outthe documentation for `plot`

: `plot(..., ..., 'o-')`

```
data = np.array([[10, -3, 10, 7, 0, 12],
[12, 12, 12, 10, 0, 12],
[7, 7, 10, 10, 0, 10],
[7, 4, 7, 7, 0, 12],
[-3, 4, 7, 4, 4, 12],
[7, 4, 4, 4, 0, 12]])
jitter_min = -0.1
jitter_max = 0.1
for a,grades in enumerate(data):
x = a*np.ones(len(grades)) + (jitter_max-jitter_min)*np.random.random(size=len(grades))+jitter_min
plt.plot(x, grades, 'o', label='Assignment #{:d}'.format(a), clip_on=False)
plt.xlabel('Assignments')
plt.ylabel('Grades')
```