Live graph for a C application

前端 未结 2 780
暗喜
暗喜 2020-12-17 01:57

I have an application which logs periodically on to a host system it could be on a file or just a console. I would like to use this data to plot a statistical graph for me.

2条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-17 02:34

    I think this can be achieved easiest using Python plus matplotlib. To achieve this there are actually multiple ways: a) integrating the Python Interpreter directly in your C application, b) printing the data to stdout and piping this to a simple python script that does the actual plotting. In the following I will describe both approaches.

    We have the following C application (e.g. plot.c). It uses the Python interpreter to interface with matplotlib's plotting functionality. The application is able to plot the data directly (when called like ./plot --plot-data) and to print the data to stdout (when called with any other argument set).

    #include 
    #include 
    #include 
    #include 
    #include 
    
    void initializePlotting() {
      Py_Initialize();
      // load matplotlib for plotting
      PyRun_SimpleString(
        "from matplotlib import pyplot as plt\n"
        "plt.ion()\n"
        "plt.show(block=False)\n"
        );
    }
    
    void uninitializePlotting() {
      PyRun_SimpleString("plt.ioff()\nplt.show()");
      Py_Finalize();
    }
    
    void plotPoint2d(double x, double y) {
    #define CMD_BUF_SIZE 256
      static char command[CMD_BUF_SIZE];
      snprintf(command, CMD_BUF_SIZE, "plt.plot([%f],[%f],'r.')", x, y);
      PyRun_SimpleString(command);
      PyRun_SimpleString("plt.gcf().canvas.flush_events()");
    }
    
    double myRandom() {
      double sum = .0;
      int count = 1e4;
      int i;
      for (i = 0; i < count; i++)
        sum = sum + rand()/(double)RAND_MAX;
      sum = sum/count;
      return sum;
    }
    
    int main (int argc, const char** argv) {
      bool plot = false;
      if (argc == 2 && strcmp(argv[1], "--plot-data") == 0)
        plot = true;
    
      if (plot) initializePlotting();
    
      // generate and plot the data
      int i = 0;
      for (i = 0; i < 100; i++) {
        double x = myRandom(), y = myRandom();
        if (plot) plotPoint2d(x,y);
        else printf("%f %f\n", x, y);
      }
    
      if (plot) uninitializePlotting();
      return 0;
    }
    

    You can build it like this:

    $ gcc plot.c -I /usr/include/python2.7 -l python2.7 -o plot
    

    And run it like:

    $ ./plot --plot-data
    

    Then it will run for some time plotting red dots onto an axis.

    When you choose not to plot the data directly but to print it to the stdout you may do the plotting by an external program (e.g. a Python script named plot.py) that takes input from stdin, i.e. a pipe, and plots the data it gets. To achieve this call the program like ./plot | python plot.py, with plot.py being similar to:

    from matplotlib import pyplot as plt
    plt.ion()
    plt.show(block=False)
    while True:
      # read 2d data point from stdin
      data = [float(x) for x in raw_input().split()]
      assert len(data) == 2, "can only plot 2d data!"
      x,y = data
      # plot the data
      plt.plot([x],[y],'r.')
      plt.gcf().canvas.flush_events()
    

    I have tested both approaches on my debian machine. It requires the packages python2.7 and python-matplotlib to be installed.

    EDIT

    I have just seen, that you wanted to plot a bar plot or such thing, this of course is also possible using matplotlib, e.g. a histogram:

    from matplotlib import pyplot as plt
    plt.ion()
    plt.show(block=False)
    values = list()
    while True:
      data = [float(x) for x in raw_input().split()]
      values.append(data[0])
      plt.clf()
      plt.hist([values])
      plt.gcf().canvas.flush_events()
    

提交回复
热议问题