### 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}");
}
```