1

I'm working on plotting a 1,000 x 1,000 grid where a white square represents a non-prime number, and a black square represents a prime number.

What it should look like is a large grid displaying numbers 0-1,000,000 and blackening any square where a prime is (so on the first and second square it is white (0 and 1) and the third and fourth square is black (2 and 3), etc). All the way up to 1,000,000

My code so far:

Imports

from math import sqrt, ceil
import matplotlib.pyplot as plt
from matplotlib import colors
import numpy as np

Generating list of primes

def all_prime(n):
    # https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * n
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i]:
            sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
    return [2] + [i for i in range(3,n,2) if sieve[i]]

Actual plotting

def prime_plot(n):
    '''
    Takes on argument (n), which is a number > 2 and produces a list of all primes up to n.
    Will then show on a plot the primes vs all numbers in range n.
    '''

    x = all_prime(n)
    y = list(range(n))

    data = np.random.rand(10, 10) * 20

    cmap = colors.ListedColormap(['white', 'black'])
    bounds = [0,10,20]
    norm = colors.BoundaryNorm(bounds, cmap.N)

    fig, ax = plt.subplots()
    ax.imshow(data, cmap=cmap, norm=norm)

    # draw gridlines
    ax.grid(which='major', axis='both', linestyle='-', color='k', linewidth=2)
    ax.set_xticks(np.arange(0, 10, 1));
    ax.set_yticks(np.arange(0, 10, 1));

    plt.show()

prime_plot(100)  

Although my intention is to generate a grid of size m x m (where m is sqrt(len(n)), I want to start by making a static sized grid.

How can I modify the above code to create what I want. Large grids seem to look really messy with matplotlib.

When changing data to use the lists I get TypeError: Image data cannot be converted to float

data = (x, y)

How do I need to convert the lists of x and y into what I need (instead of randomly generated numbers)?

  • You are plotting random numbers, not prime numbers. So I'm a bit lost on what the problem is, other than actually *using* the prime numbers previously calculated. – ImportanceOfBeingErnest Dec 05 '18 at 22:28
  • The example is using random numbers, but I want to use the list of prime numbers generated AND fit it inside of a large grid. –  Dec 05 '18 at 22:29

3 Answers3

2

I guess the idea would be to create an array of zeros (the value for "not a prime number") and set those values in it to 1 where you have a prime number. Then you need to reshape the array to an NxN grid.

import matplotlib.pyplot as plt
import numpy as np

def all_prime(n):
    # https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-
    #primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * n
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i]:
            sieve[i*i::2*i]=[False]*((n-i*i-1)//(2*i)+1)
    return [2] + [i for i in range(3,n,2) if sieve[i]]

def prime_plot(n):
    '''
    Takes on argument (n), which is a number > 2 and produces a list of all primes up to n.
    Will then show on a plot the primes vs all numbers in range n.
    '''
    N = int(np.sqrt(n))
    if N*N != n:
        raise ValueError("Need a square grid.")

    primes = np.array(all_prime(n)).astype(int)
    data = np.zeros(n)
    data[primes] = 1
    data = data.reshape(N,N)

    fig, ax = plt.subplots()
    ax.imshow(data, cmap="gray_r")

    for p in primes:
        ax.text(p%N, p//N, p, color="w", ha="center", va="center")

    plt.show()

prime_plot(100)

enter image description here

ImportanceOfBeingErnest
  • 251,038
  • 37
  • 461
  • 518
  • This is the solution. Though I am curious if there is a way to increase the speed of the program. Doing large numbers starts to take a "lot" of time. The numbers also seem to get cut off if the digits stretch too far. –  Dec 05 '18 at 23:24
  • For large numbers of `n`, please remove the `ax.text`-part... this is only for illustration. – ImportanceOfBeingErnest Dec 05 '18 at 23:25
0

Large grids seem to look really messy with matplotlib.

Just for fun, I decided to try to implement your program using Python turtle. Also, for programming practice, I turned all_prime() into a generator:

from turtle import Screen, Turtle

LIMIT = 100
SQUARE_SIZE = 40

def all_prime(n):
    """ Returns  a list of primes < n """

    # https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-
    # primes-below-n-in-python/3035188#3035188

    yield 2

    sieve = [True] * n

    for i in range(3, int(n ** 0.5) + 1, 2):
        if sieve[i]:
            sieve[i * i::2 * i] = [False] * ((n - i * i - 1) // (2 * i) + 1)

    yield from (i for i in range(3, n, 2) if sieve[i])

FONT_SIZE = SQUARE_SIZE // 2
FONT = ('Arial', FONT_SIZE, 'normal')
CURSOR_SIZE = 20
BORDER = SQUARE_SIZE
ROOT = int(LIMIT ** 0.5)

screen = Screen()
screen.setup(ROOT * SQUARE_SIZE + BORDER * 2, ROOT * SQUARE_SIZE + BORDER * 2)
screen.setworldcoordinates(-1, ROOT + 1, ROOT + 1, -1)

turtle = Turtle("square", visible=False)
turtle.penup()
turtle.goto((ROOT + 2) / 2 - 1, (ROOT + 2) / 2 - 1)

turtle.shapesize((ROOT * SQUARE_SIZE) / CURSOR_SIZE)
turtle.color("black", "white")
turtle.stamp()  # border

turtle.shapesize(SQUARE_SIZE / CURSOR_SIZE)
turtle.color("white", "black")

primes = all_prime(LIMIT)

try:
    prime = next(primes)

    for y in range(ROOT):

        if not prime:
            break

        for x in range(ROOT):

            if prime == (y * ROOT) + x:
                turtle.goto(x + 0.5, y + 0.5)
                turtle.stamp()

                turtle.sety(y + 0.5 + FONT_SIZE / SQUARE_SIZE / 2)
                turtle.write(prime, align="center", font=FONT)

                prime = next(primes)

except StopIteration:
    pass

screen.mainloop()

enter image description here

cdlane
  • 33,404
  • 4
  • 23
  • 63
  • This is an interesting take on it! I wonder how long it takes turtles to draw this all out. (Especially for really large grids) –  Dec 10 '18 at 05:04
  • @JacobPox, wrapping the `try` clause with a `screen.tracer(True)` ... `screen.tracer(False)` for speed, tossing the number writing part, reducing the square size to 2 x 2 pixels, I was able to produce a 500 x 500 square in about 7 seconds. – cdlane Dec 10 '18 at 21:23
-1

For the primer numbers generation you could use eulerlib: https://pypi.org/project/eulerlib/ This library is very useful when dealing with prime numbers.

  • The function currently being used is faster than eulerlib's. Tested on a variety of number ranges (100-1,000,000) –  Dec 05 '18 at 23:00