### Install FFMpegCore and System.Drawing.Common Packages Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/video/index.md Installs the necessary NuGet packages for video rendering using System.Drawing and FFMpegCore. This includes the core FFMpegCore library, its System.Drawing extension, and the System.Drawing.Common package. ```bash dotnet new console dotnet add package System.Drawing.Common dotnet add package FFMpegCore dotnet add package FFMpegCore.Extensions.System.Drawing.Common ``` -------------------------------- ### Manually Trigger Re-render Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-winforms/index.md Provides examples of manually triggering a re-render of the graphics. This can be done via a button click or a timer tick event, allowing for dynamic updates. ```cs private void button1_Click(object s, EventArgs e) => skglControl1.Invalidate(); ``` ```cs private void timer1_Tick(object s, EventArgs e) => skglControl1.Invalidate(); ``` -------------------------------- ### WPF UI Layout for Drawing Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/quickstart-wpf/index.md Defines the XAML structure for a WPF window, including a Canvas and an Image element. The Canvas is configured with event handlers for mouse clicks and loading, while the Window has a SizeChanged handler. This setup is used to host and display drawn graphics. ```xml ``` ```xml ``` -------------------------------- ### Create C# Console Application Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-console/index.md Creates a new C# console application project using the .NET CLI. This is the foundational step for building the application. ```bash dotnet new console ``` -------------------------------- ### Create WinForms Application Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-winforms/index.md Creates a new Windows Forms project using the .NET CLI. This is the initial step to set up the project structure. ```sh dotnet new WinForms ``` -------------------------------- ### Create WPF Application - .NET CLI Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-wpf/index.md Creates a new WPF application project using the .NET command-line interface. This is the initial step before adding dependencies for graphics drawing. ```sh dotnet new wpf ``` -------------------------------- ### Example Indexed Strings List Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md This shows an example of the `indexedStrings` list after processing. It contains various metadata strings, including program names, file paths, units, and comments, which are used to interpret ABF file data. ```python indexedStrings = ['', 'Clampex', '', 'C:/path/protocol.pro', 'some comment', 'IN 0', 'mV', 'IN 1', 'mV', 'Cmd 0', 'pA', 'Cmd 1', 'pA', 'Cmd 2', 'mV', 'Cmd 3', 'mV'] ``` -------------------------------- ### Add Maui.Graphics NuGet Packages Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-winforms/index.md Installs the necessary NuGet packages for Maui.Graphics and its SkiaSharp backend, along with the SkiaSharp Windows Forms integration. These packages enable 2D graphics rendering. ```sh dotnet add package Microsoft.Maui. Graphics dotnet add package Microsoft.Maui.Graphics.Skia dotnet add package SkiaSharp.Views.WindowsForms ``` -------------------------------- ### Add Maui.Graphics NuGet Packages Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-console/index.md Adds the required Microsoft.Maui.Graphics and Microsoft.Maui.Graphics.Skia NuGet packages to the console application. These packages provide the drawing capabilities. ```bash dotnet add package Microsoft.Maui.Graphics dotnet add package Microsoft.Maui.Graphics.Skia ``` -------------------------------- ### Python Example: Reading ABF1 Header Data Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md This code snippet provides a comprehensive example of reading the entire ABF1 header using the `readStruct` function. It systematically reads various fields, including file signature, version, acquisition parameters, and channel mappings, demonstrating a practical application of structured data reading. ```python fFileSignature = readStruct(f, "4s", 0) fFileVersionNumber = readStruct(f, "f", 4) nOperationMode = readStruct(f, "h", 8) lActualAcqLength = readStruct(f, "i", 10) nNumPointsIgnored = readStruct(f, "h", 14) lActualEpisodes = readStruct(f, "i", 16) lFileStartTime = readStruct(f, "i", 24) lDataSectionPtr = readStruct(f, "i", 40) lTagSectionPtr = readStruct(f, "i", 44) lNumTagEntries = readStruct(f, "i", 48) lSynchArrayPtr = readStruct(f, "i", 92) lSynchArraySize = readStruct(f, "i", 96) nDataFormat = readStruct(f, "h", 100) nADCNumChannels = readStruct(f, "h", 120) fADCSampleInterval = readStruct(f, "f", 122) fSynchTimeUnit = readStruct(f, "f", 130) lNumSamplesPerEpisode = readStruct(f, "i", 138) lPreTriggerSamples = readStruct(f, "i", 142) lEpisodesPerRun = readStruct(f, "i", 146) fADCRange = readStruct(f, "f", 244) lADCResolution = readStruct(f, "i", 252) nFileStartMillisecs = readStruct(f, "h", 366) nADCPtoLChannelMap = readStruct(f, "16h", 378) nADCSamplingSeq = readStruct(f, "16h", 410) sADCChannelName = readStruct(f, "10s"*16, 442) sADCUnits = readStruct(f, "8s"*16, 602) fADCProgrammableGain = readStruct(f, "16f", 730) fInstrument = readStruct(f, "16f", 922) fInstrumentOffset = readStruct(f, "16f", 986) fSignalGain = readStruct(f, "16f", 1050) fSignalOffset = readStruct(f, "16f", 1114) nDigitalEnable = readStruct(f, "h", 1436) nActiveDACChannel = readStruct(f, "h", 1440) nDigitalHolding = readStruct(f, "h", 1584) nDigitalInterEpisode = readStruct(f, "h", 1586) nDigitalValue = readStruct(f, "10h", 2588) lDACFilePtr = readStruct(f, "2i", 2048) lDACFileNumEpisodes = readStruct(f, "2i", 2056) fDACCalibrationFactor = readStruct(f, "4f", 2074) fDACCalibrationOffset = readStruct(f, "4f", 2090) nWaveformEnable = readStruct(f, "2h", 2296) nWaveformSource = readStruct(f, "2h", 2300) nInterEpisodeLevel = readStruct(f, "2h", 2304) nEpochType = readStruct(f, "20h", 2308) fEpochInitLevel = readStruct(f, "20f", 2348) fEpochLevelInc = readStruct(f, "20f", 2428) lEpochInitDuration = readStruct(f, "20i", 2508) lEpochDurationInc = readStruct(f, "20i", 2588) nTelegraphEnable = readStruct(f, "16h", 4512) fTelegraphAdditGain = readStruct(f, "16f", 4576) sProtocolPath = readStruct(f, "384s", 4898) ``` -------------------------------- ### MAUI XAML Setup for GraphicsView Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-maui/index.md This XAML defines the structure of a MAUI page, including a GraphicsView component. It references a custom drawable resource to specify what should be rendered on the view. Ensure the 'drawable' namespace is correctly mapped to your drawable class. ```xml ``` -------------------------------- ### Add NuGet Packages - .NET CLI Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-wpf/index.md Adds the required NuGet packages to a WPF project to enable drawing with Microsoft.Maui.Graphics and SkiaSharp. These packages provide the necessary drawing surfaces and APIs. ```sh dotnet add package Microsoft.Maui.Graphics dotnet add package Microsoft.Maui.Graphics.Skia dotnet add package SkiaSharp.Views.WPF ``` -------------------------------- ### Add SkiaSharp NuGet Package Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/skiasharp/quickstart-console/index.md Adds the SkiaSharp NuGet package to the C# console application project. This package provides the necessary libraries for drawing graphics. ```bash dotnet add package SkiaSharp ``` -------------------------------- ### Configure Anti-Aliasing in System.Drawing C# Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/quickstart-console/index.md This C# code illustrates how to configure anti-aliasing settings for both graphics and text rendering using the System.Drawing library. It shows how to set the SmoothingMode for graphics and various TextRenderingHint options for text, impacting the visual quality and performance of rendered elements. ```csharp // Configure anti-aliasing mode for graphics gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed; // Configure anti-aliasing mode for text gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit; gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; ``` -------------------------------- ### Install SkiaSharp and FFMpegCore Packages Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/skiasharp/video/index.md This snippet shows the bash commands to create a new .NET console project and add the necessary SkiaSharp and FFMpegCore NuGet packages to the project. These packages are essential for graphics rendering and video encoding, respectively. ```bash dotnet new console dotnet add package SkiaSharp dotnet add package FFMpegCore ``` -------------------------------- ### Draw Graphics and Save Image (C#) Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/skiasharp/quickstart-console/index.md Draws graphics onto a SkiaSharp bitmap and saves it as a JPEG file. It initializes a bitmap, clears it with a blue color, draws 100 random white lines with varying thicknesses, and then encodes and saves the bitmap to 'quickstart.jpg' with 85% quality. ```csharp using SkiaSharp; // Create an image and fill it blue SKBitmap bmp = new(640, 480); using SKCanvas canvas = new(bmp); canvas.Clear(SKColor.Parse("#003366")); // Draw lines with random positions and thicknesses Random rand = new(0); SKPaint paint = new() { Color = SKColors.White.WithAlpha(100), IsAntialias = true }; for (int i = 0; i < 100; i++) { SKPoint pt1 = new(rand.Next(bmp.Width), rand.Next(bmp.Height)); SKPoint pt2 = new(rand.Next(bmp.Width), rand.Next(bmp.Height)); paint.StrokeWidth = rand.Next(1, 10); canvas.DrawLine(pt1, pt2, paint); } // Save the image to disk SKFileWStream fs = new("quickstart.jpg");mp.Encode(fs, SKEncodedImageFormat.Jpeg, quality: 85); ``` -------------------------------- ### Re-render Graphics on Window Resize Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-winforms/index.md Attaches an event handler to the SizeChanged event of the SkiaSharp control to trigger a re-render when the window size changes. This ensures the graphics adapt to new dimensions. ```cs private void skglControl1_SizeChanged(object s, EventArgs e) => skglControl1.Invalidate(); ``` -------------------------------- ### Python Example: Reading ABF2 File Header Information Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md Demonstrates how to use the `readStruct` function to extract various pieces of information from an ABF2 file header. It opens a binary file, reads specific fields like file signature, version, and channel count, and prints the results. ```python f = open("14o08011_ic_pair.abf", 'rb') print(readStruct(f, "4s", 0)) print(readStruct(f, "I", 12)) f.close() ``` -------------------------------- ### Trigger Rendering in WPF Application Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/quickstart-wpf/index.md Defines C# event handler methods in a WPF application to trigger the rendering of graphics. These methods are called when the Canvas is loaded, the Window size changes, or the Canvas is clicked, ensuring that the graphics are redrawn appropriately in response to these events. ```cs private void myCanvas_Loaded(object sender, RoutedEventArgs e) => Render(); private void Window_SizeChanged(object sender, SizeChangedEventArgs e) => Render(); private void myCanvas_MouseDown(object sender, MouseButtonEventArgs e) => Render(); ``` -------------------------------- ### Draw Graphics with Maui.Graphics in C# Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-console/index.md Demonstrates how to use Maui.Graphics to draw shapes and export them as a PNG image from a C# console application. It initializes a bitmap context, draws a filled rectangle and several circles, and saves the result to a file named 'console.png'. ```csharp using Microsoft.Maui.Graphics; using Microsoft.Maui.Graphics.Skia; SkiaBitmapExportContext bmp = new(600, 400, 1.0f); ICanvas canvas = bmp.Canvas; canvas.FillColor = Color.FromArgb("#003366"); canvas.FillRectangle(0, 0, bmp.Width, bmp.Height); Random rand = new(0); canvas.StrokeColor = Colors.White.WithAlpha(.5f); canvas.StrokeSize = 2; for (int i = 0; i < 100; i++) { float x = rand.Next(bmp.Width); float y = rand.Next(bmp.Height); float r = rand.Next(5, 50); canvas.DrawCircle(x, y, r); } mp.WriteToFile("console.png"); ``` -------------------------------- ### Python Example: Converting Byte String to String Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md Shows how to convert a byte string, obtained from reading structured data, into a standard Python string. It uses the `.decode()` method with specific error handling to ensure proper conversion, ignoring characters that are not valid ASCII. ```python value1 = readStruct(f, "4s", 0)[0] print(value1) value2 = value1.decode("ascii", errors="ignore") print(value2) ``` -------------------------------- ### Draw Random Lines with System.Drawing in C# Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/quickstart-console/index.md This C# code snippet demonstrates how to create a bitmap, draw 10,000 random lines with varying colors on a navy background, and save the image as 'demo.png'. It utilizes the System.Drawing library and requires the System.Drawing.Common NuGet package. Proper disposal of IDisposable objects like Pen and Bitmap is managed using 'using' statements. ```csharp using System.Drawing; using Bitmap bmp = new(600, 400); using Graphics gfx = Graphics.FromImage(bmp); gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gfx.Clear(Color.Navy); Random rand = new(0); using Pen pen = new(Color.White); for (int i = 0; i < 10_000; i++) { pen.Color = Color.FromArgb(rand.Next()); Point pt1 = new(rand.Next(bmp.Width), rand.Next(bmp.Height)); Point pt2 = new(rand.Next(bmp.Width), rand.Next(bmp.Height)); gfx.DrawLine(pen, pt1, pt2); } mp.Save("demo.png"); ``` -------------------------------- ### Install Microsoft.Data.Analysis NuGet Package Source: https://github.com/swharden/csharp-data-visualization/blob/main/projects/dataframe/demo.ipynb Installs the Microsoft.Data.Analysis NuGet package, which provides the DataFrame functionality for data manipulation in .NET Interactive. This package is essential for working with tabular data structures. ```csharp #r "nuget:Microsoft.Data.Analysis" using Microsoft.Data.Analysis; ``` -------------------------------- ### Initialize and Render Graphics on Form Load (C#) Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/quickstart-winforms/index.md This C# code snippet shows how to call the Render method when a Windows Forms application's main form is initialized. This ensures that the graphics are drawn and displayed on the PictureBox as soon as the application launches. It is part of the initialization process within the Form1 constructor. ```csharp public Form1() { InitializeComponent(); Render(); } ``` -------------------------------- ### Read ABF Sweep Data for Graphing (Python) Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md Extracts a specific sweep's data (sweepY) and creates a corresponding time vector (sweepX) starting from zero. Optionally, it can convert sweep time to absolute time by adding the sweep's start time. ```python pointStart = sweepPointCount * sweepNumber pointEnd = pointStart + sweepPointCount sweepY = data[channel, pointStart:pointEnd] sweepX = np.arange(len(sweepY))*dataSecPerPoint # For absolute time: sweepX += sweepNumber * sweepLengthSec ``` -------------------------------- ### Install and Configure ScottPlot for Plotting in C# Source: https://github.com/swharden/csharp-data-visualization/blob/main/projects/dataframe/demo.ipynb Installs the ScottPlot NuGet package and registers its display type for rendering plots directly within .NET Interactive Notebooks. This enables the visualization of data using interactive plots. ```csharp // install ScottPlot and register its display type #r "nuget:ScottPlot" using Microsoft.DotNet.Interactive.Formatting; Formatter.Register(typeof(ScottPlot.Plot), (plt, writer) => writer.Write(((ScottPlot.Plot)plt).GetImageHTML()), HtmlFormatter.MimeType); ``` -------------------------------- ### Create Double Buffers and Start Rendering Thread in C# Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/double-buffer/index.md Initializes two Bitmap objects for double-buffering and starts a separate thread to continuously render graphics. This prevents the main GUI thread from being blocked during complex drawing operations. It requires the `System.Drawing` namespace and assumes a `Form` with a `Label` control named `label1`. ```csharp public static Bitmap bmpA; public static Bitmap bmpB; public Form2() { InitializeComponent(); bmpA = new Bitmap(label1.Width, label1.Height); bmpB = new Bitmap(label1.Width, label1.Height); var t = new Thread(new ThreadStart(RenderContinuously)); t.Start(); } ``` -------------------------------- ### Draw Test Pattern with Maui.Graphics ICanvas (C#) Source: https://context7.com/swharden/csharp-data-visualization/llms.txt Defines platform-agnostic rendering logic using ICanvas and demonstrates its usage with SkiaSharp for Windows Forms and console applications. The `Render.DrawTestPattern` method takes an ICanvas, width, and height to draw a navy background and random white lines. The example shows how to integrate this with SkiaSharp for both interactive controls and file output. ```csharp using Microsoft.Maui.Graphics; using SkiaSharp; using System.IO; // Define platform-agnostic rendering logic public static class Render { public static void DrawTestPattern(ICanvas canvas, float width, float height) { // Fill background canvas.FillColor = Colors.Navy; canvas.FillRectangle(0, 0, width, height); // Draw random lines var random = new Random(); canvas.StrokeColor = Colors.White; canvas.StrokeSize = 2; for (int i = 0; i < 100; i++) { float x1 = (float)random.NextDouble() * width; float y1 = (float)random.NextDouble() * height; float x2 = (float)random.NextDouble() * width; float y2 = (float)random.NextDouble() * height; canvas.DrawLine(x1, y1, x2, y2); } } } // Example usage in Windows Forms with SkiaSharp // var skglControl = new SkiaSharp.Views.Desktop.SKGLControl(); // skglControl.PaintSurface += (sender, e) => // { // var canvas = e.Surface.Canvas; // var mauiCanvas = new SkiaSharp.SkiaCanvas(); // mauiCanvas.Canvas = canvas; // Render.DrawTestPattern(mauiCanvas, skglControl.Width, skglControl.Height); // }; // Example usage in WPF (similar approach with SKElement control) // Example usage in Console (save to file) var info = new SKImageInfo(800, 600); using var surface = SKSurface.Create(info); var skCanvas = surface.Canvas; var mauiCanvas = new SkiaSharp.SkiaCanvas(); mauiCanvas.Canvas = skCanvas; Render.DrawTestPattern(mauiCanvas, 800, 600); using var image = surface.Snapshot(); using var data = image.Encode(SKEncodedImageFormat.Png, 100); using var stream = File.OpenWrite("output.png"); data.SaveTo(stream); Console.WriteLine("Image saved to output.png"); ``` -------------------------------- ### C# Bitmap Rendering: Correct IDisposable Handling with 'using' Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/quickstart-winforms/index.md This C# code snippet shows the correct way to handle IDisposable objects (Bitmap and Graphics) using the 'using' statement. This ensures that Dispose() is automatically called, preventing memory leaks and improving application stability. It's a best practice for resource management. ```csharp void ResizeBitmap() { // properly disposing IDisposable objects using (var bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height)) using (var gfx = Graphics.FromImage(bmp)) { /* rendering code */ } } ``` -------------------------------- ### Add SkiaSharp Element - XAML Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-wpf/index.md Integrates a SkiaSharp drawing surface into the WPF application's XAML. The SKElement is linked to a PaintSurface event handler where drawing commands will be executed. ```xml ``` -------------------------------- ### Raw Bitmap Creation in C# Without Libraries Source: https://context7.com/swharden/csharp-data-visualization/llms.txt Demonstrates how to create and manipulate bitmap images at the byte level without relying on any external graphics libraries. This code directly implements the BMP file format structure, allowing for low-level image generation. It includes methods for setting pixels and saving the image to a file. ```csharp public class RawBitmap { public readonly int Width; public readonly int Height; public readonly byte[] ImageBytes; public RawBitmap(int width, int height) { Width = width; Height = height; ImageBytes = new byte[width * height * 4]; // BGRA format } public void SetPixel(int x, int y, byte r, byte g, byte b) { int offset = ((Height - y - 1) * Width + x) * 4; ImageBytes[offset + 0] = b; ImageBytes[offset + 1] = g; ImageBytes[offset + 2] = r; ImageBytes[offset + 3] = 255; // Alpha } public void Save(string filename) { const int headerSize = 54; byte[] bmpBytes = new byte[ImageBytes.Length + headerSize]; // BMP signature bmpBytes[0] = (byte)'B'; bmpBytes[1] = (byte)'M'; // File size Array.Copy(BitConverter.GetBytes(bmpBytes.Length), 0, bmpBytes, 2, 4); // Image data offset Array.Copy(BitConverter.GetBytes(headerSize), 0, bmpBytes, 10, 4); // DIB header size bmpBytes[14] = 40; // Image dimensions Array.Copy(BitConverter.GetBytes(Width), 0, bmpBytes, 18, 4); Array.Copy(BitConverter.GetBytes(Height), 0, bmpBytes, 22, 4); // Bits per pixel (32-bit BGRA) Array.Copy(BitConverter.GetBytes(32), 0, bmpBytes, 28, 2); // Image size Array.Copy(BitConverter.GetBytes(ImageBytes.Length), 0, bmpBytes, 34, 4); // Copy pixel data Array.Copy(ImageBytes, 0, bmpBytes, headerSize, ImageBytes.Length); File.WriteAllBytes(filename, bmpBytes); } } // Usage example var bitmap = new RawBitmap(400, 300); // Draw gradient for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { byte red = (byte)(x * 255 / bitmap.Width); byte green = (byte)(y * 255 / bitmap.Height); byte blue = 128; bitmap.SetPixel(x, y, red, green, blue); } } bitmap.Save("gradient.bmp"); Console.WriteLine("Image saved successfully!"); ``` -------------------------------- ### Draw Graphics - C# Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-wpf/index.md Implements the PaintSurface event handler to draw graphics onto the SkiaSharp canvas. It sets a background color and then draws multiple random circles with specified properties. ```cs private void SKElement_PaintSurface(object sender, SkiaSharp.Views.Desktop.SKPaintSurfaceEventArgs e) { ICanvas canvas = new SkiaCanvas() { Canvas = e.Surface.Canvas }; canvas.FillColor = Colors.Navy; canvas.FillRectangle(0, 0, (float)SkElement1.ActualWidth, (float)SkElement1.ActualHeight); canvas.StrokeColor = Colors.White.WithAlpha(.5f); canvas.StrokeSize = 2; for (int i = 0; i < 100; i++) { float x = Random.Shared.Next((int)SkElement1.ActualWidth); float y = Random.Shared.Next((int)SkElement1.ActualHeight); float r = Random.Shared.Next(5, 50); canvas.DrawCircle(x, y, r); } } ``` -------------------------------- ### Set Target Framework for NAudio Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/audio/naudio/index.md Configures the project file to target Windows, which is a requirement for using the NAudio library for microphone access. This XML snippet is added to the project file to specify the target framework. ```xml net6.0-windows ``` -------------------------------- ### C# Audio Input and Plotting with NAudio and ScottPlot Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/audio/level/index.md This C# code snippet demonstrates setting up audio input using NAudio's WaveInEvent and visualizing the audio levels in real-time using ScottPlot. It initializes the plot, configures audio recording settings, and updates the plot and a progress bar as audio data becomes available. Dependencies include NAudio for audio capture and ScottPlot for plotting. ```csharp public partial class Form1 : Form { NAudio.Wave.WaveInEvent? Wave; readonly double[] AudioValues; int SampleRate = 44100; int BitDepth = 16; int ChannelCount = 1; int BufferMilliseconds = 20; public Form1() { InitializeComponent(); AudioValues = new double[SampleRate * BufferMilliseconds / 1000]; formsPlot1.Plot.AddSignal(AudioValues, SampleRate / 1000); formsPlot1.Plot.YLabel("Level"); formsPlot1.Plot.XLabel("Time (milliseconds)"); formsPlot1.Refresh(); } private void Form1_Load(object sender, EventArgs e) { for (int i = 0; i < NAudio.Wave.WaveIn.DeviceCount; i++) { var caps = NAudio.Wave.WaveIn.GetCapabilities(i); comboBox1.Items.Add(caps.ProductName); } } private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { if (Wave is not null) { Wave.StopRecording(); Wave.Dispose(); for (int i = 0; i < AudioValues.Length; i++) AudioValues[i] = 0; formsPlot1.Plot.AxisAuto(); } if (comboBox1.SelectedIndex == -1) return; Wave = new NAudio.Wave.WaveInEvent() { DeviceNumber = comboBox1.SelectedIndex, WaveFormat = new NAudio.Wave.WaveFormat(SampleRate, BitDepth, ChannelCount), BufferMilliseconds = BufferMilliseconds }; Wave.DataAvailable += WaveIn_DataAvailable; Wave.StartRecording(); formsPlot1.Plot.Title(comboBox1.SelectedItem.ToString()); } void WaveIn_DataAvailable(object? sender, NAudio.Wave.WaveInEventArgs e) { for (int i = 0; i < e.Buffer.Length / 2; i++) AudioValues[i] = BitConverter.ToInt16(e.Buffer, i * 2); } private void timer1_Tick(object sender, EventArgs e) { int level = (int)AudioValues.Max(); // auto-scale the maximum progressbar level if (level > pbVolume.Maximum) pbVolume.Maximum = level; pbVolume.Value = level; // auto-scale the plot Y axis limits var currentLimits = formsPlot1.Plot.GetAxisLimits(); formsPlot1.Plot.SetAxisLimits( yMin: Math.Min(currentLimits.YMin, -level), yMax: Math.Max(currentLimits.YMax, level)); // request a redraw using a non-blocking render queue formsPlot1.RefreshRequest(); } } ``` -------------------------------- ### Draw Graphics with Maui.Graphics Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/maui.graphics/quickstart-winforms/index.md Implements the PaintSurface event handler for a SkiaSharp control to draw graphics using Maui.Graphics. It sets a background color and draws random circles, demonstrating basic drawing operations. ```cs private void skglControl1_PaintSurface(object sender, SkiaSharp.Views.Desktop.SKPaintGLSurfaceEventArgs e) { ICanvas canvas = new SkiaCanvas() { Canvas = e.Surface.Canvas }; canvas.FillColor = Colors.Navy; canvas.FillRectangle(0, 0, skglControl1.Width, skglControl1.Height); canvas.StrokeColor = Colors.White.WithAlpha(.5f); canvas.StrokeSize = 2; for (int i = 0; i < 100; i++) { float x = Random.Shared.Next(skglControl1.Width); float y = Random.Shared.Next(skglControl1.Height); float r = Random.Shared.Next(5, 50); canvas.DrawCircle(x, y, r); } } ``` -------------------------------- ### Add Using Statements for FFMpegCore Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/system.drawing/video/index.md Includes the required namespaces for using FFMpegCore functionalities, including pipes, frame sources, and System.Drawing extensions. ```csharp using FFMpegCore; using FFMpegCore.Pipes; using FFMpegCore.Extensions.System.Drawing.Common; ``` -------------------------------- ### Calculate Data Location and Size for ABF2 Files Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md Calculates data parameters for ABF2 files by referencing the section map and protocol information. It extracts data byte start, point count, channel count, data rate, and sweep count. ```python dataByteStart = _sectionMap.DataSection[0]*BLOCKSIZE dataPointCount = _sectionMap.DataSection[2] channelCount = _sectionMap.ADCSection[2] dataRate = int(1e6 / _protocolSection.fADCSequenceInterval) dataSecPerPoint = 1/dataRate sweepCount = lActualEpisodes ``` -------------------------------- ### Calculate Data Location and Size for ABF1 Files Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/dev/pyabf/index.md Determines the starting byte position, data point count, channel count, data rate, and sweep count for ABF1 files. It relies on predefined constants like BLOCKSIZE and protocol-specific variables. ```python dataByteStart = lDataSectionPtr*BLOCKSIZE dataByteStart += nNumPointsIgnored dataPointCount = lActualAcqLength channelCount = nADCNumChannels dataRate = int(1e6 / fADCSampleInterval) dataSecPerPoint = 1/dataRate sweepCount = lActualEpisodes ``` -------------------------------- ### Capture and Display Real-Time Audio Waveform (C#) Source: https://context7.com/swharden/csharp-data-visualization/llms.txt Captures microphone audio using NAudio's WasapiCapture and visualizes the real-time waveform using ScottPlot. Supports 16-bit/32-bit PCM and 32-bit IEEE Float audio formats. The input is audio samples from the default audio endpoint, and the output is a visual representation of the waveform plotted to an image file. ```csharp using NAudio.CoreAudioApi; using NAudio.Wave; using ScottPlot; // Initialize audio capture device var enumerator = new MMDeviceEnumerator(); var device = enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia); var audioDevice = new WasapiCapture(device); // Create buffer for audio samples (10 milliseconds) WaveFormat fmt = audioDevice.WaveFormat; double[] audioValues = new double[fmt.SampleRate * 10 / 1000]; // Setup ScottPlot for visualization var plt = new ScottPlot.Plot(800, 400); plt.AddSignal(audioValues, fmt.SampleRate / 1000); plt.YLabel("Level"); plt.XLabel("Time (milliseconds)"); plt.SetAxisLimitsY(-.5, .5); // Handle incoming audio data audioDevice.DataAvailable += (sender, e) => { int bytesPerSamplePerChannel = fmt.BitsPerSample / 8; int bytesPerSample = bytesPerSamplePerChannel * fmt.Channels; int bufferSampleCount = Math.Min(e.Buffer.Length / bytesPerSample, audioValues.Length); // Convert PCM bytes to double values if (bytesPerSamplePerChannel == 2 && fmt.Encoding == WaveFormatEncoding.Pcm) { for (int i = 0; i < bufferSampleCount; i++) audioValues[i] = BitConverter.ToInt16(e.Buffer, i * bytesPerSample); } else if (bytesPerSamplePerChannel == 4 && fmt.Encoding == WaveFormatEncoding.IeeeFloat) { for (int i = 0; i < bufferSampleCount; i++) audioValues[i] = BitConverter.ToSingle(e.Buffer, i * bytesPerSample); } }; audioDevice.StartRecording(); // Update plot periodically (e.g., in a timer) plt.Render(); plt.SaveFig("waveform.png"); // Cleanup audioDevice.StopRecording(); audioDevice.Dispose(); ``` -------------------------------- ### C# Graphics Model Interface and BallPitModel Implementation Source: https://context7.com/swharden/csharp-data-visualization/llms.txt Defines the `IGraphicsModel` interface for animated graphics and implements a `BallPitModel` for a bouncing ball simulation. It handles model reset, resize, drawing, and advancement logic, with dependencies on `Microsoft.Maui.Graphics`. ```csharp using Microsoft.Maui.Graphics; // Define model interface public interface IGraphicsModel : IDrawable { void Reset(float width, float height); void Resize(float width, float height); void Draw(ICanvas canvas, float width, float height); void Advance(float time = 1); } // Implement bouncing ball simulation public class BallPitModel : IGraphicsModel { public float Width { get; set; } public float Height { get; set; } private class Ball { public float X, Y, Radius; public float XVel, YVel; public Color Color; } private readonly Ball[] Balls; private readonly Random Rand = new(); public BallPitModel(int ballCount = 100) { Balls = Enumerable.Range(0, ballCount).Select(x => new Ball()).ToArray(); } public void Reset(float width, float height) { Resize(width, height); foreach (Ball ball in Balls) { ball.X = (float)Rand.NextDouble() * Width; ball.Y = (float)Rand.NextDouble() * Height; ball.Radius = (float)Rand.NextDouble() * 10 + 5; double direction = Rand.NextDouble() * 2 * Math.PI; float speed = (float)Rand.NextDouble() * 2 + .5f; ball.XVel = (float)Math.Sin(direction) * speed; ball.YVel = (float)Math.Cos(direction) * speed; ball.Color = Color.FromHsv((float)Rand.NextDouble(), .5f, 1); } } public void Resize(float width, float height) { Width = width; Height = height; } public void Advance(float time = 1) { foreach (Ball ball in Balls) { ball.X += ball.XVel; ball.Y += ball.YVel; // Bounce off edges if (ball.X < ball.Radius || ball.X > Width - ball.Radius) ball.XVel *= -1; if (ball.Y < ball.Radius || ball.Y > Height - ball.Radius) ball.YVel *= -1; // Keep in bounds ball.X = Math.Clamp(ball.X, ball.Radius, Width - ball.Radius); ball.Y = Math.Clamp(ball.Y, ball.Radius, Height - ball.Radius); } } public void Draw(ICanvas canvas, float width, float height) { canvas.FillColor = Colors.Navy; canvas.FillRectangle(0, 0, width, height); foreach (Ball ball in Balls) { canvas.FillColor = ball.Color; canvas.FillCircle(ball.X, ball.Y, ball.Radius); } } public void Draw(ICanvas canvas, RectangleF dirtyRect) { Draw(canvas, dirtyRect.Width, dirtyRect.Height); } } ``` -------------------------------- ### Activate Selected Recording Device (C#) Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/audio/level/index.md Handles the selection of a recording device from the ComboBox. It stops and disposes of any previous recording session, then initializes and starts a new `WaveInEvent` with specified audio format and buffer settings. ```csharp int SampleRate = 44100; int BitDepth = 16; int ChannelCount = 1; int BufferMilliseconds = 20; NAudio.Wave.WaveInEvent? Wave; private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { if (Wave is not null) { Wave.StopRecording(); Wave.Dispose(); } Wave = new NAudio.Wave.WaveInEvent() { DeviceNumber = comboBox1.SelectedIndex, WaveFormat = new NAudio.Wave.WaveFormat(SampleRate, BitDepth, ChannelCount), BufferMilliseconds = BufferMilliseconds }; Wave.DataAvailable += WaveIn_DataAvailable; Wave.StartRecording(); } ``` -------------------------------- ### List Available Audio Input Devices with C# NAudio Source: https://github.com/swharden/csharp-data-visualization/blob/main/website/content/audio/naudio/index.md Retrieves and lists all available audio input devices on the system using NAudio. It iterates through the device count and prints the product name for each device, including the 'Microsoft Sound Mapper'. Note that device names might be truncated. ```csharp for (int i = -1; i < NAudio.Wave.WaveIn.DeviceCount; i++) { var caps = NAudio.Wave.WaveIn.GetCapabilities(i); Console.WriteLine($"{i}: {caps.ProductName}"); } ```