4

I have a dictionary band1 as shown below, I want to print out a graph based on the first and last element of each list in the dictionary. The first element of each list on the x axis, is a frequency and the last element is a reception strength and should be on the y axis. Eg, 10812 has a strength of 16 etc

band1 = {'channel1': [10564, 2112.8, 1922.8, 0],
         'channel10': [10787, 2157.4, 1967.4, 11],
         'channel11': [10812, 2162.4, 1972.4, 16],
         'channel12': [10837, 2167.4, 1977.4, 46],
         'channel2': [10589, 2117.8, 1927.8, 29],
         'channel3': [10612, 2122.4, 1932.4, 0],
         'channel4': [10637, 2127.4, 1937.4, 40],
         'channel5': [10662, 2132.4, 1942.4, 54],
         'channel6': [10687, 2137.4, 1947.4, 0],
         'channel7': [10712, 2142.4, 1952.4, 50],
         'channel8': [10737, 2147.4, 1957.4, 19],
         'channel9': [10762, 2152.4, 1962.4, 24]}

I have no problem sorting this, channel1 -> channel12 but what are some nice ways to print a pretty graph, the amount of entries in the dictionary can vary with there being more or less channels.

Aleksei Zyrianov
  • 2,294
  • 1
  • 24
  • 32
Paul
  • 5,756
  • 6
  • 48
  • 78
  • 1
    Have you considered using a graphing library like [pyplot](http://matplotlib.org/api/pyplot_api.html)? It should be pretty easy to do with pyplot. – NG. Apr 26 '13 at 15:48
  • Thanks I am interested to see what libraries there are but also to see is there any nice way without downloading anything extra. This will just be printed out in console. Will have a look at pyplot now cheers. – Paul Apr 26 '13 at 15:50
  • I'm not aware of any ASCII-based graphing solutions, but you could probably put something together by hand quite easily. If the first and last elements of each list are the x and y axes respectively, how would you indicate the channel names, or does it not matter? It might help if you gave an simple example of how the resultant graph should look. – Aya Apr 26 '13 at 16:02
  • @Paul It would be very hard to graph something solely by printing. A graphing library is much more easier to use. If you don't want to download anything extra, you can always try Tkinter (the native graphics library), but it is a little harder to learn. – Rushy Panchal Apr 26 '13 at 16:06
  • related: [Command-line Unix ASCII-based charting / plotting tool](http://stackoverflow.com/q/123378/4279) – jfs Apr 26 '13 at 18:36
  • Time travelers: Also consider https://stackoverflow.com/a/43414849/2184122 – Robert Lugg Jun 11 '19 at 21:07

1 Answers1

6

Here's an algorithm of point diagram, as simple and naive as it could be. Of course, its performance is far from being performed and could be optimized, as well as the output could have some axes and numbers on it.

HEIGHT = 10
WIDTH = 40
MARKER = '*'
FILL_CHARACTER = ' '

coords = [(ch[0], ch[3]) for ch in band1.values()]


# Convert to coordinates of a desired ASCII area

xmin = min(c[0] for c in coords)
xmax = max(c[0] for c in coords)
kx = (WIDTH - 1)  / (xmax - xmin)

ymin = min(c[1] for c in coords)
ymax = max(c[1] for c in coords)
ky = (HEIGHT - 1) / (ymax - ymin)

acoords = [(round((c[0] - xmin) * kx),
            round((c[1] - ymin) * ky)) for c in coords]

# Actually draw the graph

for y in range(HEIGHT, -1, -1):
    chars = []
    for x in range(WIDTH):
        if (x, y) in acoords:
            chars.append(MARKER)
        else:
            chars.append(FILL_CHARACTER)
    print(''.join(chars))

Results to:

              *                         
                     *                 *
          *                             

    *                                   
                            *           
                         *         *    
                                *       

*      *          *                     

If x coordinates are unique, it can be quite easily modified to draw column or line diagrams.

E.g. for case of bars:

HEIGHT = 10
WIDTH = 40
MARKER = '*'
FILL_CHARACTER = ' '

coords = [(ch[0], ch[3]) for ch in band1.values()]
coords.sort(key=lambda ch: ch[1])

xmin = min(c[0] for c in coords)
xmax = max(c[0] for c in coords)
kx = (WIDTH - 1)  / (xmax - xmin)

ymin = min(c[1] for c in coords)
ymax = max(c[1] for c in coords)
ky = (HEIGHT - 1) / (ymax - ymin)

acoords = {}
for c in coords:
    x = round((c[0] - xmin) * kx)
    y = round((c[1] - ymin) * ky)
    if x not in acoords:
        acoords[x] = y
    else:
        acoords[x] = max(acoords[x], y)

for y in range(HEIGHT, -1, -1):
    chars = []
    for x in range(WIDTH):
        if acoords.get(x, 0) >= y:
            chars.append(MARKER)
        else:
            chars.append(FILL_CHARACTER)
    print(''.join(chars))

Results to:

              *                         
              *      *                 *
          *   *      *                 *
          *   *      *                 *
    *     *   *      *                 *
    *     *   *      *      *          *
    *     *   *      *   *  *      *   *
    *     *   *      *   *  *   *  *   *
    *     *   *      *   *  *   *  *   *
****************************************
Aleksei Zyrianov
  • 2,294
  • 1
  • 24
  • 32