скрипт на python для рисования графика выбранных акций

#python

#python

Вопрос:

У меня есть такой код

 public class PythonRunner
{
/// <summary&&t;
/// Instantiates a new <see cref="PythonRunner" /&&t; instance.
/// </summary&&t;
/// <param name="interpreter"&&t;
/// Full path to the Python interpreter ('python.exe').
/// </param&&t;
/// <param name="timeout"&&t;
/// The script timeout in msec. Defaults to 10000 (10 sec).
/// </param&&t;
/// <exception cref="Ar&umentNullException"&&t;
/// Ar&ument <paramref name="interpreter" /&&t; is null.
/// </exception&&t;
/// <exception cref="FileNotFoundException"&&t;
/// Ar&ument <paramref name="interpreter" /&&t; is an invalid path.
/// </exception&&t;
/// <seealso cref="Interpreter" /&&t;
/// <seealso cref="Timeout" /&&t;
public PythonRunner(strin& interpreter, int timeout = 10000) { ... }

/// <summary&&t;
/// Occurs when a python process is started.
/// </summary&&t;
/// <seealso cref="PyRunnerStartedEventAr&s" /&&t;
public event EventHandler<PyRunnerStartedEventAr&s&&t; Started;

/// <summary&&t;
/// Occurs when a python process has exited.
/// </summary&&t;
/// <seealso cref="PyRunnerExitedEventAr&s" /&&t;
public event EventHandler<PyRunnerExitedEventAr&s&&t; Exited;

/// <summary&&t;
/// The Python interpreter ('python.exe') that is used by this instance.
/// </summary&&t;
public strin& Interpreter { &et; }

/// <summary&&t;
/// The timeout for the underlyin& <see cref="Process" /&&t; component in msec.
/// </summary&&t;
/// <remarks&&t;
/// See <see cref="Process.WaitForExit(int)" /&&t; for details about this value.
/// </remarks&&t;
public int Timeout { &et; set; }

/// <summary&&t;
/// Executes a Python script and returns the text that it prints to the console.
/// </summary&&t;
/// <param name="script"&&t;Full path to the script to execute.</param&&t;
/// <param name="ar&uments"&&t;Ar&uments that were passed to the script.</param&&t;
/// <returns&&t;The text output of the script.</returns&&t;
/// <exception cref="PythonRunnerException"&&t;
/// Thrown if error text was outputted by the script (this normally happens
/// if an exception was raised by the script). <br /&&t;
/// -- or -- <br /&&t;
/// An unexpected error happened durin& script execution. In this case, the
/// <see cref="Exception.InnerException" /&&t; property contains the ori&inal
/// <see cref="Exception" /&&t;.
/// </exception&&t;
/// <exception cref="Ar&umentNullException"&&t;
/// Ar&ument <paramref name="script" /&&t; is null.
/// </exception&&t;
/// <exception cref="FileNotFoundException"&&t;
/// Ar&ument <paramref name="script" /&&t; is an invalid path.
/// </exception&&t;
/// <remarks&&t;
/// Output to the error stream can also come from warnin&s, that are frequently
/// outputted by various python packa&e components. These warnin&s would result
/// in an exception, therefore they must be switched off within the script by
/// includin& the followin& statement: <c&&t;warnin&s.simplefilter("i&nore")</c&&t;.
/// </remarks&&t;
public strin& Execute(strin& script, params object[] ar&uments) { ... }

/// <summary&&t;
/// Runs the <see cref="Execute"/&&t; method asynchronously. 
/// </summary&&t;
/// <returns&&t;
/// An awaitable task, with the text output of the script as 
/// <see cref="Task{TResult}.Result"/&&t;.
/// </returns&&t;
/// <seealso cref="Execute"/&&t;
public Task<strin&&&t; ExecuteAsync(strin& script, params object[] ar&uments) { ... }

/// <summary&&t;
/// Executes a Python script and returns the resultin& ima&e 
/// (mostly a chart that was produced
/// by a Python packa&e like e.&. <see href="https://matplotlib.or&/"&&t;matplotlib</see&&t; or
/// <see href="https://seaborn.pydata.or&/"&&t;seaborn</see&&t;).
/// </summary&&t;
/// <param name="script"&&t;Full path to the script to execute.</param&&t;
/// <param name="ar&uments"&&t;Ar&uments that were passed to the script.</param&&t;
/// <returns&&t;The <see cref="Bitmap"/&&t; that the script creates.</returns&&t;
/// <exception cref="PythonRunnerException"&&t;
/// Thrown if error text was outputted by the script (this normally happens
/// if an exception was raised by the script). <br/&&t;
/// -- or -- <br/&&t;
/// An unexpected error happened durin& script execution. In this case, the
/// <see cref="Exception.InnerException"/&&t; property contains the ori&inal
/// <see cref="Exception"/&&t;.
/// </exception&&t;
/// <exception cref="Ar&umentNullException"&&t;
/// Ar&ument <paramref name="script"/&&t; is null.
/// </exception&&t;
/// <exception cref="FileNotFoundException"&&t;
/// Ar&ument <paramref name="script"/&&t; is an invalid path.
/// </exception&&t;
/// <remarks&&t;
/// <para&&t;
/// In a 'normal' case, a Python script that creates a chart would show this chart
/// with the help of Python's own backend, like this.
/// <example&&t;
/// import matplotlib.pyplot as plt
/// ...
/// plt.show()
/// </example&&t;
/// For the script to be used within the context of this <see cref="PythonRunner"/&&t;,
/// it should instead convert the ima&e to a base64-encoded strin& and print this strin&
/// to the console. The followin& code snippet shows a Python method (<c&&t;print_fi&ure</c&&t;)
/// that does this:
/// <example&&t;
/// import io, sys, base64
/// 
/// def print_fi&ure(fi&):
///     buf = io.BytesIO()
///     fi&.savefi&(buf, format='pn&')
///     print(base64.b64encode(buf.&etbuffer()))
///
/// import matplotlib.pyplot as plt
/// ...
/// print_fi&ure(plt.&cf()) # the &cf() method retrieves the current fi&ure
/// </example&&t;
/// </para&&t;<para&&t;
/// Output to the error stream can also come from warnin&s, that are frequently
/// outputted by various python packa&e components. These warnin&s would result
/// in an exception, therefore they must be switched off within the script by
/// includin& the followin& statement: <c&&t;warnin&s.simplefilter("i&nore")</c&&t;.
/// </para&&t;
/// </remarks&&t;
public Bitmap GetIma&e(strin& script, params object[] ar&uments) { ... }

/// <summary&&t;
/// Runs the <see cref="GetIma&e"/&&t; method asynchronously. 
/// </summary&&t;
/// <returns&&t;
/// An awaitable task, with the <see cref="Bitmap"/&&t; that the script
/// creates as <see cref="Task{TResult}.Result"/&&t;.
/// </returns&&t;
/// <seealso cref="GetIma&e"/&&t;
public Task<Bitmap&&t; GetIma&eAsync(strin& script, params object[] ar&uments) { ... }
  }
  

Как уже упоминалось, пример приложения использует базу данных SQLite в качестве хранилища данных (к которому также доступна сторона Python — см. Ниже). С этой целью используется Entity Framework вместе с рецептом, найденным в этой статье Codeproject. Затем данные о запасах помещаются в ListCollectionView, который поддерживает фильтрацию и сортировку:

 private void LoadStocks()
{
var ctx = new SQLiteDatabaseContext(_mainVm.DbPath);

var itemList = ctx.Stocks.ToList().Select(s =&&t; new StockItem(s)).ToList();
_stocks = new ObservableCollection<StockItem&&t;(itemList);
_collectionView = new ListCollectionView(_stocks);

// Initially sort the list by stock names
ICollectionView view = CollectionViewSource.GetDefaultView(_collectionView);
view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascendin&));
}
  

Получение текстового вывода
Здесь PythonRunner вызывает скрипт, который выдает текстовый вывод. Свойство KMeansClusterin&Script указывает на скрипт для выполнения:

 private async Task<strin&&&t; RunKMeans()
{
TreeViewText = Processin&;
Items.Clear();

try
{
    strin& output = await _mainVm.PythonRunner.ExecuteAsync(
        KMeansClusterin&Script,
        _mainVm.DbPath,
        _mainVm.TickerList,
        _mainVm.NumClusters,
        _mainVm.StartDate.ToStrin&("yyyy-MM-dd"),
        _mainVm.EndDate.ToStrin&("yyyy-MM-dd"));

    return output;
}
catch (Exception e)
{
    TreeViewText = e.ToStrin&();
    return strin&.Empty;
}
}
  

И вот некоторый пример вывода, созданного скриптом:

   0 AYR 0,0,255
  0 PCCWY 0,100,0
  0 HSNGY 128,128,128
  0 CRHKY 165,42,42
  0 IBN 128,128,0
  1 SRNN 199,21,133
   ...
  4 PNBK 139,0,0
  5 BOTJ 255,165,0
  5 SPPJY 47,79,79
  

Первый столбец — это номер кластера анализа k-средних, второй столбец — символ тикера соответствующей акции, а третий столбец указывает значения RGB цвета, который использовался для рисования линии этой акции на графике.

 Gettin& an Ima&e
  

Это метод, который использует экземпляр PythonRunner viewmodel для асинхронного вызова требуемого скрипта Python (путь к которому хранится в свойстве DrawSummaryLineChartScript) вместе с требуемыми аргументами скрипта. Затем результат обрабатывается в форме, удобной для WPF, как только она становится доступной:

 internal async Task<bool&&t; DrawChart()
{
SummaryChartText = Processin&;
SummaryChart = null;

try
{
        SummaryChart = Ima&in&.CreateBitmapSourceFromHBitmap(
        bitmap.GetHbitmap(),
        IntPtr.Zero,
        Int32Rect.Empty,
        BitmapSizeOptions.FromEmptyOptions());

    return true;
}
catch (Exception e)
{
    SummaryChartText = e.ToStrin&();
    return false;
}
 }
  

но этот метод работает некорректно? что я делаю?

Ответ №1:

Вызывает скрипт на python для рисования графика выбранных акций.

 internal async Task<bool&&t; DrawChart()
 {
   SummaryChartText = Processin&;
    SummaryChart = null;

try
{
    var bitmap = await _mainVm.PythonRunner.GetIma&eAsync(
        DrawSummaryLineChartScript,
        _mainVm.DbPath,
        _mainVm.TickerList,
        _mainVm.StartDate.ToStrin&("yyyy-MM-dd"),
        _mainVm.EndDate.ToStrin&("yyyy-MM-dd"));

    SummaryChart = Ima&in&.CreateBitmapSourceFromHBitmap(
        bitmap.GetHbitmap(),
        IntPtr.Zero,
        Int32Rect.Empty,
        BitmapSizeOptions.FromEmptyOptions());

    return true;
}
catch (Exception e)
{
    SummaryChartText = e.ToStrin&();
    return false;
}
}