commit 9520c1fa4a7b75a16c9fa9b9f6662894681cb686 Author: maier_st Date: Sat Sep 2 09:24:59 2023 +0200 Neuerstellung - Quelle: https://github.com/oxyplot/oxyplot diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..3d294a4 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,167 @@ +Contribute to OxyPlot +===================== + +OxyPlot is driven by the community and contributors like you. We are excited that you're interested to help us move forward and improve OxyPlot. + +The flow when contributing to OxyPlot is as follows: + +1. Add issue (bug or new feature) +2. If the issue needs to be clarified, wait for some feedback +3. Commit your changes +4. Update the change log and contributors files +4. Create a pull request + +Note that your contributions must be your own work and licensed under the same terms as OxyPlot. + + +## Reporting bugs + +First, search the issue tracker to see if the bug is already there. + +It is very helpful to get the generated code (use `CTRL+ALT+C` in the plot control) and report (`CTRL+ALT+R`) of the bug plot. You can also take a screen shot and paste it into the description. + +Please use markdown to format your code blocks with [syntax highlighting](https://help.github.com/articles/github-flavored-markdown/#syntax-highlighting) to make it easier for everyone to read. + +You could also use services like https://snipt.org or https://gist.github.com to share code snippets. + +A bug report should include: + +- the platform you are building for (Windows Forms, WPF, Xamarin Forms etc.) +- the framework version (netcore3, net47 etc.) +- the version of OxyPlot you are using +- description of the issue +- sample code to reproduce the issue +- what you expect and what is the actual behaviour + + +## Suggesting new features + +First, search the issue tracker to see if the feature is already there. + +A feature request should include: + +- description of the feature +- a drawing/image, if possible + +It could be a good idea to wait for some feedback before starting to work on a new feature. +Not all features are general enough to fit into this library. +We don't want you to waste time on something that might not be merged in the end. + + +## Creating your own fork + +1. Log in to GitHub and open the [oxyplot](https://github.com/oxyplot/oxyplot/) origin repository. Click the "Fork" button to create your own fork of the repository. +2. Create a clone on your local system: `git clone https://github.com/yourusername/oxyplot.git` + + +## Branch + +The repository contains two branches: + +- `master` - the release branch (stable channel) +- `develop` - the main branch with the latest development changes (pre-release channel) + +You should base your work on the `develop` branch. + +See [A successful git branching model](https://nvie.com/posts/a-successful-git-branching-model/) for more information about the branching model in use. + +Create a branch for the bugfix/feature you want to work on: `git branch bugfix-some-error` + +Checkout the branch: `git checkout bugfix-some-error` + + +## Commit your changes + +Before you start committing, please define your [full name](https://help.github.com/articles/setting-your-username-in-git/) and [e-mail](https://help.github.com/articles/setting-your-email-in-git/) address in git. + +Please follow the style of the other messages in the commit history. Explain the intentions for the change and include the issue number. Include the issue number in the commit message, e.g. "#9945". + +Please follow the coding-style: + +- write StyleCop compliant code +- include XML comments for all methods, properties and fields +- do not use #regions +- use linq method syntax (not query syntax) +- keep it simple + +To commit your changes, use the git command: `git commit -m ` + +When you are ready to make a pull request, please + +- [Rebase](https://git-scm.com/docs/git-rebase) to the latest commit of the origin +- [Squash](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) each logical change to a single commit + +More info about rebasing + +- https://git-scm.com/book/en/v2/Git-Branching-Rebasing +- https://blog.sourcetreeapp.com/2012/08/21/merge-or-rebase/ +- https://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html +- https://ariejan.net/2011/07/05/git-squash-your-latests-commits-into-one/ +- https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History +- https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase-i + +Finally, push your commits: `git push` + + +## Requirements for a pull request + +- Include the issue number +- Include examples or unit tests for the change / new feature +- Update the CHANGELOG.md file +- Update the CONTRIBUTORS and AUTHORS files if you are not already listed there + + +## Creating a pull request + +- Open the GitHub page for your fork and create a "Pull Request" (PR) + + +## Merging + +When the PR is submitted, a build will automatically be trigged. +A team member will then review the PR, and merge the branch if everything looks OK. + +If there are some issues with the PR, you should +- update your code and commit changes +- clean up the git history with rebase or squash +- force push: `git push -f` + +The PR will be updated automatically when you push your changes. + + +## Contributing to the documentation + +The documentation is located in the [docs](https://github.com/oxyplot/docs) repository. +See the README.md file for information about how to build the documentation. +Please contribute by creating pull requests! + + +## Contributing to the website + +The source of the [oxyplot.github.io](https://oxyplot.github.io/) web site can be found in the [oxyplot.github.io](https://github.com/oxyplot/oxyplot.github.io) repository. +Please contribute by creating pull requests! + +The web-site is built by [GitHub](https://github.com/) with [Jekyll](https://jekyllrb.com/). + + +## Common rules + +To prevent the issue (backlog) list to grow indefinitely, an issue will be closed when you are not responding to requests by a project developer. +We need your help, so we will not close an issue by desire. But when you are not answering to a request by for a month we will close the issue. +If this happens in accident, feel free to re-open the issue... + +The issue reporter can close the issue because: + +- he/she verified the fix/change +- found out that it is not an OxyPlot issue but some problem in his/her code + +In case the reporter does not respond to a request: + +- a project developer is allowed to close the issue (after one month) + +Someone can take over the issue from the reporter, when: + +- he/she can reproduce the issue +- has some sample code +- has more time/information to assist in the resolution +- responds to requests by a project developer diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..4b4e074 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,38 @@ + + + + +### Steps to reproduce + +1. +2. +3. + +Platform: +.NET version: + +### Expected behaviour + +Tell us what should happen + +### Actual behaviour + +Tell us what happens instead +Can you also include a screen shot? + + + + +### Feature description + +Write a description of the feature. How should it work? How should it look? +Include some graphics if this could help! + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..118ffba --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,16 @@ +Fixes # . + +### Checklist + +- [ ] I have included examples or tests +- [ ] I have updated the change log +- [ ] I am listed in the CONTRIBUTORS file +- [ ] I have cleaned up the commit history (use rebase and squash) + +### Changes proposed in this pull request: + +- +- +- + +@oxyplot/admins diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..8d510b7 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,65 @@ +name: "CodeQL" + +on: + push: + branches: [ 'develop', 'master' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ 'develop' ] + schedule: + - cron: '4 12 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: windows-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'csharp' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup .NET Core + uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 3.1.x + 6.0.x + + - name: Setup MSBuild.exe + uses: microsoft/setup-msbuild@v1.1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + - name: Build + run: dotnet build Source/OxyPlot.CI.sln --configuration Release + + - name: MSBuild + run: msbuild Source\OxyPlot.CI.sln -p:Configuration=Release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml new file mode 100644 index 0000000..d3f7068 --- /dev/null +++ b/.github/workflows/dotnetcore.yml @@ -0,0 +1,34 @@ +name: Build on Windows +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 6.0.x + 7.0.x + + - name: Build + run: dotnet build Source/OxyPlot.CI.sln --configuration Release + + - name: Run unit tests + run: dotnet test Source/OxyPlot.CI.sln --configuration Release + + - name: Setup MSBuild.exe + uses: microsoft/setup-msbuild@v1.1 + + - name: MSBuild + run: msbuild Source\OxyPlot.CI.sln -p:Configuration=Release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51338be --- /dev/null +++ b/.gitignore @@ -0,0 +1,247 @@ + +# Created by https://www.gitignore.io/api/visualstudio + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ + +# OxyPlot specific +Output/ +launchSettings.json + +# Rider +.idea/ diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..bc7e39c --- /dev/null +++ b/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of OxyPlot authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS file. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. +# Please notify the first person on the list to be added here. + +Oystein Bjorke +DNV GL AS +LECO® Corporation +TrainerRoad, LLC diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..decfba4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,511 @@ +# Change Log +All notable changes to this project will be documented in this file. + +## Unreleased + +### Added +- Example to Show/Hide Legend (#1470) +- Example of BarSeries stacked and with labels (#1979) +- Example of issue with AreaSeries tracker (#1982) +- Example for CategoryAxis with custom MajorStep and uncentered ticks (#1971) +- BarSeries.LabelAngle property (#1870) +- Support HiDPI for WinForms examples (#1597) +- Border properties on PathAnnotation to match functionality in TextAnnotation (#1900) +- Expanded `IntervalBarSeries` and `TornadoBarSeries` to allow for varied label positions and angles (#2027) +- VectorSeries (#107) + +### Changed +- Make consistent BaseValue and BaseLine across BarSeries, LinearBarSeries, and HistogramSeries +- Factor out common project properties to `Directory.Build.props` (#1937) +- Remove support for .NET Standard 1.X, as .NET Framework 4.6.2 supports .NET Standard 2.0 (#1937) +- Remove support for .NET Core 3.1, as it is end-of-life soon (#1937) +- Move example projects to .NET Framework 4.6.2 and .NET 6.0 (#1937) +- Run tests on both .NET Framework 4.6.2 and .NET 6.0 (#1937) +- Add support for .NET 7.0 (#1937) +- Update SkiaSharp to Version 2.88.3 + +### Removed +- Support for .NET Framework 4.0 and 4.5 (#1839) +- Unused LabelColor property from TornadoBarSeries, IntervalBarSeries, and RectangleBarSeries (#2030) + +### Fixed +- Placement of BarSeries labels when stacked (#1979) +- SystemInvalidException in LineSeries when only Double.Nan values are added (#1991) +- Issue with tracking AreaSeries with monotonic data points (#1982) +- Incorrect coloring of TwoColorLineSeries +- HitTest when IsLegendVisible is false (#1975) +- Font weight not being applied in ImageSharp (#2006) +- SkiaSharp - Fix use of obsolete functions (#1937) +- Dashed lines are solid when exporting via SkiaSharp.SvgExporter (#1674) + +## [2.1.2] - 2022-12-03 + +### Added +- Add LineThickness property to TrackerControl (#1831) +- Add properties for `MinimumSegmentLength` to series and annotations (#1853) +- Add fractal examples for PolygonAnnotation and PolylineAnnotations (#1853) +- Add `AxisPreference` to `PlotManipulator` +- Add MinimumMajorIntervalCount and MaximumMajorIntervalCount Axis Properties (#24) +- Add VisualStudioToolsManifest.xml to add components to the Visual Studio Designer toolbox (#1446) + +### Changed +- Change default `MinimumSegmentLength` to `2` and remove limits for series and annotations with simple geometry (#1853) +- Improve performance of `StairStepSeries`, particularly when zoomed in and X is monotonic or when consecutive points have equal Y components +- `StairStepSeries` renders a horizontal line when a point with a valid X component and invalid Y component follows a valid point + +### Removed + +### Fixed +- WPF - OxyPlot doesn't render inside a Popup (#1796) +- Odd behavior of zooming of Logarithmic axis in Cartesian plot (#1825) +- SkiaSharp.WPF - OxyPlot doesn't render inside an ElementHost (#1800) +- NullReference in SkiaSharp WPF renderer if UIElement has no PresentationSource (#1798) +- WPF DPI Regression (#1799) +- Code generation for escape sequences in strings (#1824) +- Axes not always honoring AbsoluteMinimum/AbsoluteMaximum and/or MinimumRange/MaximumRange properties (#1812) +- WindowsForms tracker no longer clipping outside PlotView boundaries (#1863) +- CategoryAxis.ItemsSource without BarSeries (#1847) +- Histogram now rendering properly when using logarithmic Y axis (#740) +- Fix ExampleLibrary build errors in certain code pages (#1890) +- LineBarSeries now rendering properly when using logarithmic scale (#740) +- Fix for double.Epsilon zero check that fails on some architectures (#1924) + +## [2.1.0] - 2021-10-02 + +### Added +- Made Legend Items clickable to toggle series visibility (#644) +- Added properties LegendKey and SeriesGroupName to Series, allowing grouping series between multiple legends and/or within same legend (#644) +- OxyPlot.ImageSharp (#1188) +- WPF ExampleBrowser can display transposed versions of examples (#1402) +- Support for transposable Annotations (#1417) +- Support for NET40 (#1452) +- Support for high DPI for WPF (#149) +- EdgeRenderingMode property to PlotElement, allowing customization of the way edges are treated by the renderer (#1428, #1358, #1077, #843, #145) +- Color palettes Viridis, Plasma, Magma, Inferno and Cividis (#1505) +- Renderer based on SkiaSharp, including exporters for PNG, JPEG, PDF and SVG (#1509) +- Example for Issue #1524: HitTracker IndexOutOfRangeException with HeatMapSeries +- Text shaping support to SkiaRenderContext (#1520) +- PlotView based on SkiaRenderContext (OxyPlot.SkiaSharp.Wpf) (#1515) +- DrawImage support to OxyPlot.ImageSharp (#1530) +- Dpi support to OxyPlot.ImageSharp (#1530) +- Dash support to OxyPlot.ImageSharp +- Clipping support to OxyPlot.ImageSharp +- JpegExporter for OxyPlot.ImageSharp +- Multi-line aligned text rendering example +- WindowsForms ExampleBrowser can display transposed versions of examples (#1535) +- Example for Issue #1545 showing the use of different line endings +- Support for unix line endings in OxyPlot.ImageSharp, OxyPlot.Svg, and OxyPlot.Pdf (#1545) +- Multi-Line Text support to SkiaRenderContext (#1538) +- Added title clipping to PlotModel (#1510) +- Added LabelStep and LabelSpacing to contour series (#1511) +- Example for Issue #1481 showing text rendering with emoji +- Native Clipping for OxyPlot.SvgRenderContext (#1564) +- Examples of full plot area polar plots with non-zero minimums (#1586) +- Read-Only collection interfaces for .NET 4.0 (#1600) +- Add PlotModel.AssignColorsToInvisibleSeries property to control whether invisible series are included or skipped when assigning automatic colors (#1599) +- Overlapping bar series (#1265) +- `AxisPosition.All` for axes which need a margin on all sides of the plot area (#1574) +- IRenderContext.ClipCount property (#1593) +- Additional parameters for HistogramSeries LabelFormatString +- Absolute screen-space axis margins (#1569) +- netstandard2.0 TargetFramework (#1668) +- Add a PlotView.TextMeasurementMethod property to allow using the much faster GlyphTypeface based measurement at runtime (#1673) +- OxyPlot.Wpf.XamlRenderContext - this doesn't use StreamGeometry and can be used for rendering to XAML (#1673) +- SkiaRenderContext.MiterLimit property (#1690) +- Example for Issue #1685 showing spurious lines in the ContourSeries +- Example for Issue #1716 showing poor tick spacing on DateTimeAxis with interval types of Weeks or Years +- Example for label placement on BarSeries with non-zero BaseValue (#1726) +- ExtrapolationLineSeries as described in #1740 to allow to display pre-defined intervals of a line series with a different style than the rest. +- Added DataRange, unit tests and examples as support for ExtrapolationLineSeries. +- Add control over how far from the series the tracker fires (#1736) +- Add option to check distance for result between data points (#1736) +- Legend.AllowUseFullExtent property to control whether legends should be able to use the full extent of the plot (#1743) +- Legend.ShowInvisibleSeries property to control whether invisible series should be shown on the legend (#1730) +- OxyPlot.SkiaSharp.Wpf PlotView support for simple render transforms (#1785) + +### Changed +- Legends model (#644) +- Default behaviour is now plot without Legend (#644) +- Moved WPF Plot component to Oxyplot.Contrib.Wpf (#1399) +- ErrorColumnSeries changed to ErrorBarSeries, also works in transposed mode (#1402) +- Moved reporting functionality to separate projects (#1403) +- Moved reporting functionality to oxyplot-reporting repository (#1403) +- Change IPlotModel.Render to take an OxyRect (#1425) +- Merge UIElement and SelectableElement into Element (#1426) +- Upgrade to .NET Core 3.1 (#1488) +- DrawRectangle(...), DrawLine(...), DrawEllipse(...), DrawPolygon(...) and related overloads in IRenderContext and related extensions in RenderingExtensions now require an EdgeRenderingMode +- Default color palette for LinearColorAxis from Jet to Viridis (#1505) +- Extract most of the functionality from OxyPlot.Wpf into OxyPlot.Wpf.Shared to allow code sharing with other WPF PlotViews (#1515) +- WPF ExampleBrowser can switch between Canvas and SkiaSharp renderers (#1515) +- OxyPlot.ImageSharp now targets .NET Standard 1.3 (#1530) +- SkiaRenderContext does not apply pixel snapping when rendering to vector graphic (#1539) +- Mark OxyPlot.PdfExporter and OxyPlot.Pdf.PdfExporter as obsolete (#1527) +- Replace Axis.DesiredSize by Axis.DesiredMargin, change signature of Axis.Measure(...) (#453) +- Axis renderers now render all ticks they are provided (#1580) +- Auto margins don't reserve space for axis labels if axis range is fixed (#1577) +- CategoryAxis should not contain rendering information about BarSeries (#741) +- CategorizedSeries changed to BarSeriesBase (#741) +- System.Drawing.Common references updated to 4.7.0 (#1608) +- Invisible series are assigned automatic colors by default, configurable with PlotModel.AssignColorsToInvisibleSeries property that defaults to true (#1599) +- StemSeries, AreaSeries, TwoColorAreaSeries, and StairStepSeries use `ActualMarkerColor` (#1630) +- Axes with `AxisPosition.None` make no contribution to margins (#1574) +- `AngleAxis` has position `AxisPosition.All` by default (#1574) +- Clipping API changed from SetClip(...) and ResetClip() to PushClip(...) and PopClip() (#1593) +- Remove TileMapAnnotation examples from automated testing (#1667) +- Optimize clipping calls (#1661) +- Mark CandleStickAndVolumeSeries as obsolete (#1661) +- Implement StreamGeometry-based implementations of DrawEllipses, DrawLine, DrawLineSegments and DrawRectangle(s) which improves the rendering speed on WPF (#1673) +- Change algorithm of ContourSeries.JoinContourSegments(). This should improve performance in most cases, but will cause labels to appear in different spots than before (#1685) +- Updated Series.cd with ExtrapolationLineSeries and removed classes that do not exist anymore + +### Removed +- Remove PlotModel.Legends (#644) +- ColumnSeries - functionality is replaced by transposed BarSeries (#1402) +- Copy to text report Ctrl+Alt+R (#1403) +- Remove exporter Background properties (#1409) +- Remove OxyThickness Width and Height properties (#1429) +- RenderingExtensions.DrawRectangleAsPolygon(...) extension methods. IRenderContext.DrawRectangle(...) with an appropriate EdgeRenderingMode can be used instead. +- SkiaSharp.PdfExporter.Dpi property (#1591) +- Axis.UpdateFromSeries(...) and Series.UpdateValidData() (#741) +- Support for IRenderContext implementations without native clipping (#1593) +- CohenSutherlandClipping and SutherlandHodgmanClipping (#1593) +- DrawClippedXxx(...) extensions in RenderingExtensions (#1661) +- PathAnnotation.ClipText property - text is now always clipped (#1661) +- CanvasRenderContext.UseStreamGeometry property - this functionality is replaced by the new XamlRenderContext (#1673) + +### Fixed +- Legend font size is not affected by DefaultFontSize (#1396) +- ErrorBarSeries, IntervalBarSeries and TornadoBarSeries work correctly in transposed mode (#1402) +- Exception when rendering polygon with no points (#1410) +- Custom tracker strings can cause exception in histogram chart (#1455) +- OxyPlot.WindowsForms package description (#1457) +- NullReference in VolumeSeries if no data in Items list (#1491) +- Possible out-of-bounds exception in HeatMapSeries HitTest (#1524) +- WPF CanvasRenderContext draws ellipses too small by half stroke thickness (#1537) +- Text measurement and rendering in OxyPlot.ImageSharp +- ExampleLibrary reporting annotation-only PlotModels as transposable (#1544) +- Auto plot margin not taking width of labels into account (#453) +- WPF PlotView still focusable when Focusable is false (#1440) +- Disposing a SkiaRenderContext can mess up fonts from another SkiaRenderContext instance (#1573) +- Display of ampersands in OxyPlot.WindowsForms Tracker (#1585) +- Full Plotarea Polar plot rendering with non-zero minimum values (#1586) +- Auto margins are set incorrectly if Axis.TitleFontSize is set to non-default value (related to #1577) +- Incomplete rendering of AreaSeries in some situations (#1512) +- ColumnSeries / BarSeries not working with more than one value-axis (#729) +- OxyPlot.SkiaSharp.SvgExporter plot background color (#1619) +- MinimumPadding incorrect when MaximumPadding is non-zero (#1625) +- Don't clip zerocrossing axis lines within plot bounds (#1441) +- Incorrect margins when using Color Axes with AxisPosition.None (#1574) +- OpenStreetMap example (#1642) +- Incorrect clipping in TwoColorAreaSeries (#1678) +- ScreenMin and ScreenMax on Horizontal and Vertical Axes depends on plot bounds (#1652) +- Windows Forms clipping last line of measured text (#1659) +- Inconsistent Zooming behaviour (#1648) +- ContourSeries produce fake connections (#1685) +- Zero-crossing axis bounds (#1708) +- Incorrect label placement on BarSeries with non-zero BaseValue (#1726) +- LineAnnotation Text Placement on Reversed Axes (#1741) +- Image opacity in WinForms and Core Drawing (#1766) +- Fix specified Visual is not an ancestor of this Visual issue in WPF rendering (#1787) + +## [2.0.0] - 2019-10-19 +### Added +- WindowsForms and Wpf support .NET Core 3.0 (#1331) +- PngExporter based on System.Common.Drawing (.NET Core) (#1263) +- New polar plot axes filling the full plot area (#1056) +- Support for three colors in histogram series (#1305) +- Command to copy plot to the clipboard in Windows Forms (Ctrl-C) (#1297) +- New `InterpolationAlgorithm` property in LineSeries and PolylineAnnotation (#494) +- Catmull-Rom spline interpolation algorithms (#494) +- FontSize, FontWeight and FontFamily on Wpf.TextAnnotation (#1023) +- RectangleSeries (#1060) +- InvalidNumberColor on Wpf.LinearColorAxis (#1087) +- ContinuousHistogramSeries (#1145) +- Multiline text support for PortableDocumentFont (#1146) +- Workaround for text vertical alignment in SVG Export to accomodate viewers which don't support dominant-baseline (#459, #1198) +- Support for transposed (X and Y axis switched) plots with XYAxisSeries (#1334) +- Color property on HistogramItem (#1347) +- Count property on HistogramSeries (#1347) +- Bug in HistogramHelpers.Collect when using out-of-order bin breaks (#1476) + +### Changed +- OxyPlot.Core changed to target netstandard 1.0 and net45 (#946, #1147) +- OxyPlot.ExampleLibrary changed to target netstandard 1.0 and net45 (#946, #1147) +- OxyPlot.Wpf, OxyPlot.WindowsForms, OxyPlot.Pdf changed to target net45 (#946) +- Place label below negative ColumnSeries (#1119) +- Use PackageReference instead of packages.config +- Migrated NUnit v2 to v3 and added test adapter +- TrackerControl reuses existing ContentControl when a new hit tracker result uses the same template as the currently shown tracker (#1281) +- Overhaul HistogramHelpers (#1345) +- OxyPlot.Windows (UWP) moved to oxyplot-uwp repository (#1378) +- Make the PngExporters consistent (#1390) +- Silverlight project moved to separate repository (#1049) +- WP8 project moved to separate repository (#1050) +- Windows8 project moved to separate repository (#1103) +- Avalonia project moved to separate repository +- Xamarin projects moved to separate repository +- Xwt project moved to separate repository +- GTK# projects moved to separate repository +- SharpDX project moved to separate repository + +### Deprecated +- OxyPlot.WP8 package. Use OxyPlot.Windows (UWP) instead (#996) + +### Removed +- LabelFontSize property from HistogramSeries (#1309) +- Smooth property from LineSeries and PolylineAnnotation (#494) +- Support for net40 (#960) + +### Fixed +- Manipulation when using touch is not working in Windows (#1011) +- Ensure a suitable folder is used when creating a temporary file for PNG export in Oxyplot.GtkSharp (#1034) +- RangeColorAxis is not rendered correctly if the axis is reversed (#1035) +- OxyMouseEvents not caught due to InvalidatePlot() in WPF (#382) +- When Color Property of LineSeries is set Markers are not shown (#937) +- Change from linear to logarithmic axis does not work (#1067) +- OxyPalette.Interpolate() throws exception when paletteSize = 1 (#1068) +- Infinite loop in LineAnnotation (#1029) +- OverflowException when zoomed in on logarithmic axis (#1090) +- ScatterSeries with DateTimeAxis/TimeSpanAxis (#1132) +- Exporting TextAnnotation with TextColor having 255 alpha to SVG produces opaque text (#1160) +- Chart is not updated when top and bottom are not visible (#1219) +- Candle overlap each candle (#623) +- CandleStick is overlapped when item.Open == item.Close in the CandleStickAndVolumeSeries (#1245) +- Out of memory exception and performance issue with Catmull-Rom Spline (#1237) +- Cache and Dispose Brush and Pen objects used by GraphicsRenderContext (#1230) +- Add checks for non-positive StrokeThickess and LineStyle.None in various places (#1312) +- Fixed references to RectangleItem in HistogramSeries +- Fix AxisChangedEventArgs.DeltaMaximum in Axes.Reset (#1306) +- Fixed Tracker for RectangleBarSeries (#1171) +- RectangleSeries doesn't render Labels (related to #1334) +- LineSeries line legend placement with reversed X axis (related to #1334) +- HistogramSeries label placement inconsistent (related to #1334) +- TwoColorLineSeries and ThreeColorLineSeries don't work with reversed Y axis (related to #1334) +- Issue with SVG always containing the xml headers (#1212) +- In WPF, make sure the axes are initalized when the Model is set before the PlotView has been loaded (#1303) +- MinimumSegmentLength not working for LineSeries (#1044) +- rendering issues with MagnitudeAxisFullPlotArea (#1364) +- OxyPlot.Core.Drawing PngExporter background when exporting to stream (#1382) +- Windows Forms clipping last line of rendered text (#1124, #1385) +- Dispose background brush in OxyPlot.Core.Drawing PngExporter (#1392) + +## [1.0.0] - 2016-09-11 +### Added +- Added OxyPlot.SharpDX.Wpf NuGet package +- Added DirectX 9.1-10.1 feature level support for SharpDX renderer +- Added SharpDX based renderer and WPF control with SharpDX render (#124) +- Added MinimumMajorStep and MinimumMinorStep to Axes.Axis (#816) +- Added support for vertical X axis to HeatMapSeries (#535) +- Added fall-back rectangle rendering to HeatMapSeries (#801) +- Added logarithmic HeatMapSeries support (#802) and example +- Axis.MaximumRange to limit the zoom (#401) +- Added OxyPlot.Mobile NuGet package to combine the mobile platforms into a single package (#362) +- Support for XWT (#295) +- TwoColorAreaSeries (#299) +- Delta values in AxisChangedEventArgs (#276) +- Git source server (added GitLink build step) (#267,#266) +- iOS PlotView ZoomThreshold/AllowPinchPastZero for use with KeepAspectRatioWhenPinching=false (#359) +- CandleStickAndVolumeSeries and VolumeSeries (#377) +- Axis.DesiredSize property (#383) +- WPF wrapper for BoxPlotSeries (#434) +- Capability to display mean value to BoxPlotSeries (#440) +- LinearBarSeries for WPF (#506) +- TitleToolTip in PlotModel (#508) +- TextColor property on WPF Axis (#452) +- ThreeColorLineSeries (#378) +- CI of the Xamarin.Android, Xamarin.iOS and Xamarin.Forms packages (#274) +- PlotModel.LegendLineSpacing (#622) +- Legend rendering for LinearBarSeries (#663) +- LegendMaxHeight property in PlotModel and Wpf.Plot (#668) +- Support for a Xamarin Forms UWP project with sample app (#697) +- ListBuilder for building lists by reflection (#705) +- F# example (#699) +- Support for discontinuities in AreaSeries (#215) +- Support for Windows Universal 10.0 apps (#615) +- Support Unicode in OxyPlot.Pdf (#789) +- TouchTrackerManipulator (#787) +- Extracted visible window search code from CandleStickSeries and made a generic version in XYSeries. Used it to optimize AreaSeries performance. (#834) +- Optimized rendering performance of RectangleBarSeries (#834). +- PdfExporter implementing IExporter (#845) +- Color minor and major ticks differently (#417) +- Support for PieSeries in OxyPlot.Wpf (#878) +- Filter in example browser (#118) +- Support for tooltips on WPF annotations +- Support for tracker in OxyPlot.GtkSharp +- Improve tracker style (Windows Forms) (#106) +- Font rendering in OxyPlot.GtkSharp improved by using Pango (#972) +- Improved LineSeries performance (#834) +- Fixed bug causing axes titles to not display in OxyPlot.GtkSharp (#989) + +### Changed +- Fixed closing file stream for PdfReportWriter when PdfReportWriter is closed or disposed of. (#892) +- Renamed OxyPlot.WindowsUniversal to OxyPlot.Windows (#242) +- Changed OxyPlot.Xamarin.Forms to require OxyPlot.Mobile dependency instead of each separate NuGet. (#362) +- Renamed OxyPlot.XamarinIOS to OxyPlot.MonoTouch (#327) +- Renamed OxyPlot.XamarinAndroid to OxyPlot.Xamarin.Android (#327) +- Renamed OxyPlot.XamarinForms to OxyPlot.Xamarin.Forms (#327) +- Renamed OxyPlot.XamarinForms.iOS to OxyPlot.Xamarin.Forms.Platform.iOS (#327) +- Renamed OxyPlot.XamarinFormsIOS to OxyPlot.Xamarin.Forms.Platform.iOS.Classic (#327) +- Renamed OxyPlot.XamarinFormsAndroid to OxyPlot.Xamarin.Forms.Platform.Android (#327) +- Renamed OxyPlot.XamarinFormsWinPhone to OxyPlot.Xamarin.Forms.Platform.WP8 (#327) +- Changed OxyPlot.Xamarin.Android target to Android level 10 (#223) +- Separated WPF Plot and PlotView (#252, #239) +- Current CandleStickSeries renamed to OldCandleStickSeries, replaced by a faster implementation (#369) +- Invalidate plot when ItemsSource contents change (INotifyCollectionChanged) on WPF only (#406) +- Xamarin.Forms references updated to 1.5.0.6447 (#293, #439) +- Change OxyPlot.Xamarin.Forms.Platform.Android target to Android level 15 (#439) +- Changed OxyPlot.Xamarin.Forms to portable Profile259 (#439) +- PlotController should not intercept input per default (#446) +- Changed DefaultTrackerFormatString for BoxPlotSeries (to include Mean) (#440) +- Changed Constructor of BoxPlotItem (to include Mean) (#440) +- Changed Axis, Annotation and Series Render() method (removed model parameter) +- Changed PCL project to profile 259, SL5 is separate now (#115) +- Extracted CreateReport() and CreateTextReport() from PlotModel (#517) +- Renamed GetLastUpdateException to GetLastPlotException and added the ability to see render exceptions(#543) +- Move TileMapAnnotation class to example library (#567) +- Change to semantic versioning (#595) +- Change GTKSharp3 project to x86 (#599) +- Change OxyPlot.Xamarin.Android to API Level 15 (#614) +- Add Xamarin.Forms renderer initialization to PlotViewRenderer (#632) +- Marked OxyPlot.Xamarin.Forms.Platform.*.Forms.Init() obsolete (#632) +- Throw exception if Xamarin.Forms renderer is not 'initialized' (#492) +- Make numeric values of DateTimeAxis compatible with ToOADate (#660) +- Make struct types immutable (#692) +- Implement IEquatable for struct types (#692) +- BoxPlotItem changed to reference type (#692) +- Move Xamarin projects to new repository (#777) +- Remove CandleStickSeries.Append (#826) +- Change MinorInterval calculation, add unit test (#133) +- Rewrite LogarithmicAxis tick calculation (#820) +- Change Axis methods to protected virtual (#837) +- Move CalculateMinorInterval and CreateTickValues to AxisUtilities (#837) +- Change default number format to "g6" in Axis base class (#841) +- Push packages to myget.org (#847) +- Change the default format string to `null` for TimeSpanAxis and DateTimeAxis (#951) + +### Removed +- StyleCop tasks (#556) +- OxyPlot.Metro project (superseded by OxyPlot.WindowsUniversal) (#241) +- PlotModel.ToSvg method. Use the SvgExporter instead. (#347) +- Constructors with parameters, use default constructors instead. (#347) +- Axis.ShowMinorTicks property, use MinorTickSize = 0 instead (#347) +- ManipulatorBase.GetCursorType method (#447) +- Model.GetElements() method +- Remove SL4 support (#115) +- Remove NET35 support (#115) +- PlotElement.Format method, use StringHelper.Format instead +- EnumerableExtensions.Reverse removed (#677) +- ListFiller (#705) + +### Fixed +- Added check to LineAnnotation.GetScreenPoints to check if ActualMaximumX==ActualMinimumX for non-curved lines. (#1029) +- Incorrect placment of axis title of axes with AxisDistance (#1065) +- SharpDX control not being rendered when loaded +- SharpDX out of viewport scrolling. +- Multiple mouse clicks not being reported in OxyPlot.GtkSharp (#854) +- StemSeries Tracking to allow tracking on tiny stems (#809) +- Fixed PDFRenderContext text alignment issues for rotated text (#723) +- HeatMapSeries.GetValue returns NaN instead of calculating a wrong value in proximity to NaN (#256) +- Tracker position is wrong when PlotView is offset from origin (#455) +- CategoryAxis should use StringFormat (#415) +- Fixed the dependency of OxyPlot.Xamarin.Forms NuGet (#370) +- Add default ctor for Xamarin.Forms iOS renderer (#348) +- Windows Phone cursor exception (#345) +- Bar/ColumSeries tracker format string bug (#333) +- Fix exception for default tracker format strings (#265) +- Fix center-aligned legends (#79) +- Fix Markdown links to tag comparison URL with footnote-style links +- WPF dispatcher issue (#311, #309) +- Custom colors for scatters (#307) +- Rotated axis labels (#303,#301) +- Floating point error on axis labels (#289, #227) +- Performance of CandleStickSeries (#290) +- Tracker text for StairStepSeries (#263) +- XamarinForms/iOS view not updating when model is changed (#262) +- Improved WPF rendering performance (#260, #259) +- Null reference with MVVM binding (#255) +- WPF PngExporter background (#234) +- XamlExporter background (#233) +- .NET 3.5 build (#229) +- Support WinPhone 8.1 in core NuGet package (#161) +- Draw legend line with custom pattern (#356) +- iOS pan/zoom stability (#336) +- Xamarin.Forms iOS PlotViewRenderer crash (#458) +- Inaccurate tracker when using LogarithmicAxis (#443) +- Fix reset of transforms in WinForms render context (#489) +- Fix StringFormat for TimeSpanAxis not recognizing f, ff, fff, etc (#330) +- Fix LineSeries SMOOTH=True will crash WinForms on right click (#499) +- Fix PlotView leak on iOS (#503) +- This PlotModel is already in use by some other PlotView control (#497) +- LegendTextColor not synchronized between wpf.Plot and InternalModel (#548) +- Legend in CandleStickSeries does not scale correctly (#554) +- Fix CodeGenerator exception for types without parameterless ctor (#573) +- Migrate automatic package restore (#557) +- Fix rendering of rotated 'math' text (#569, #448) +- WPF export demo (#568) +- Fixing a double comparison issue causing infinite loop (#587) +- Fix null reference exception when ActualPoints was null rendering a StairStepSeries (#582) +- Background color in the Xamarin.Forms views (#546) +- IsVisible change in Xamarin.Forms.Platform.iOS (#546) +- Rendering math text with syntax error gets stuck in an endless loop (#624) +- Fix issue with MinimumRange not taking Minimum and Maximum values into account (#550) +- Do not set default Controller in PlotView ctor (#436) +- Corrected owner type of Wpf.PathAnnotation dependency properties (#645) +- Fixed partial plot rendering on Xamarin.Android (#649) +- Default controller should not be shared in WPF PlotViews (#682) +- PositionAtZeroCrossing adds zero crossing line at wrong position (#635) +- Implement AreaSeries.ConstantY2 (#662) +- Null reference exception in ScatterSeries{T} actual points (#636) +- Code generation for HighLowItem (#634) +- Axis.MinimumRange did not work correctly (#711) +- FillColor in ErrorColumnSeries (#736) +- XAxisKey and YAxisKey added to Wpf.Annotations (#743) +- Fix HeatMapSeries cannot plot on Universal Windows (#745) +- Set Resolution in WinForms PngExporter (#754) +- Axis should never go into infinite loop (#758) +- Exception in BarSeriesBase (#790) +- Vertical Axes Title Font Bug (#474) +- Support string[] as ItemsSource in CategoryAxis (#825) +- Horizontal RangeColorAxis (#767) +- LogarithmicAxis sometimes places major ticks outside of the axis range (#850) +- LineSeries with smoothing raises exception (#72) +- Exception when legend is outside and plot area is small (#880) +- Axis alignment with MinimumRange (#794) +- Fixed strange number formatting when using LogarithmicAxis with very large or very small Series (#589) +- Fixed LogarithmicAxis to no longer freeze when the axis is reversed (#925) +- Prevent endless loop in LogarithmicAxis (#957) +- Fixed WPF series data not refreshed when not visible (included WPF LiveDemo) +- Fixed bug in selection of plot to display in OxyPlot.GtkSharp ExampleBrowser (#979) +- Fixed non-interpolation of HeatMapSeries in OxyPlot.GtkSharp (#980) +- Fixed axis min/max calc and axis assignment for CandleStick + VolumeSeries (#389) +- Fixed drawing of plot backgrounds in OxyPlot.GtkSharp (#990) + +## [0.2014.1.546] - 2014-10-22 +### Added +- Support data binding paths ("Point.X") (#210) +- Support for Xamarin.Forms (#204) +- Support for Windows Universal apps (#190) +- Improve TrackerFormatString consistency (#214) +- Support LineColor.BrokenLineColor +- LabelFormatString for ScatterSeries (#12) + +### Changed +- Changed tracker format strings arguments (#214) +- Rename OxyPenLineJoin to LineJoin +- Rename LineStyle.Undefined to LineStyle.Automatic + +### Fixed +- Improved text rendering for Android and iOS (#209) +- Custom shape outline for PointAnnotation (#174) +- Synchronize Wpf.Axis.MinimumRange (#205) +- TrackerHitResult bug (#198) +- Position of axis when PositionAtZeroCrossing = true (#189) +- Expose ScatterSeries.ActualPoints (#201) +- Add overridable Axis.FormatValueOverride (#181) +- PngExporter text formatting (#170) + +[Unreleased]: https://github.com/oxyplot/oxyplot/compare/v2.1.0...HEAD +[2.1.0]: https://github.com/oxyplot/oxyplot/compare/v2.0.0...v2.1.0 +[2.0.0]: https://github.com/oxyplot/oxyplot/compare/v1.0.0...v2.0.0 +[1.0.0]: https://github.com/oxyplot/oxyplot/compare/v0.2014.1.546...v1.0.0 +[0.2014.1.546]: https://github.com/oxyplot/oxyplot/compare/v0.0.1...v0.2014.1.546 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7e77a3a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..8449c26 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,156 @@ +# This is the official list of people who have contributed +# to the OxyPlot repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. + +# People submitting code should be listed in this file (by email address). + +# Names should be added to this file like so: +# Name + +# Please keep the list sorted. + +Adrien Mercier +Alexei Shcherbakov +Anders Musikka +Auriou +Bartłomiej Szypelow +benjaminrupp +Benoit Blanchon <> +BobLd +br +brantheman +Brannon King +Bryan Freeman +Brian Lim +Caleb Clarke +Carl Reinke +Carlos Anderson +Carlos Teixeira +Chase Long +Choden Konigsmark +classicboss302 +csabar +Curt Mullin +Cyril Martin +Dan Aizenstros +danpaul88 +darrelbrown +David Funk +David Laundav +David Wong +DJDAS +DNV GL AS +Doeharrrck +Don Syme +DotNetDoctor +efontana2 +elliatab +Elia Herzog +Elmar Strittmatter +episage +eric +Fabian Nitsche +Federico Coppola +Francois Botha +Frank Tore Sæther +Garrett +GaryDev <112358055+garydev10@users.noreply.github.com> +Geert van Horrik +Gimly +Herman Eldering +Iain Nicol +Ilja Nosik +Ilya Skriblovsky +Iurii Gazin +IzStriker +Jānis Kiršteins +jaykul +Jens Krumsieck +Jeremy Koritzinsky +Jeremie Magnette +jezza323 +Johan +Johan20D +Jonathan Arweck +Jonathan Shore +julien.bataille +Just Slon +Justin Morgan +Kaplas80 +kc1212 +kenny_evoleap +Kenny Nygaard +Kevin Crowell +Kyle Pulvermacher +LECO® Corporation +Levi Botelho +Linquize +lsowen +Luka B +Nils Haferkemper +Matt Ickstadt +Matt Williams +Matthew Leibowitz +Memphisch +Mendel Monteiro-Beckerman +Menno Deij - van Rijswijk +methdotnet +Michael Fox <16841316+foxmja@users.noreply.github.com> +Michael Hieke +Mikant +mirolev +Mitch-Connor +moes_leco +moljac +mroth +mrtncls +myd7349 +Oleg Tarasov +Oystein Bjorke +Patrice Marin +Peter-B- +Philippe AURIOU +Piotr Warzocha +Poul Erik Venø +Régis Boudin +Rik Borger +Rok Lampret +ryang +Sarah Müller +Senen Fernandez +Sergey Miryanov +Scott W Harden +Shankar Mathiah Nanjundan +Shun-ichi Goto +Soarc +Soren Holstebroe +Stefan Rado +stefan-schweiger +Steve Hoelzer +Surfin Bird +Sven Dummis +Taldoras +Tandy Carmichael +Tasos Stamadianos +Thorsten Claff +thepretender +tephyrnex +Thomas Ibel +Tomasz Cielecki +ToplandJ +twsl <45483159+twsI@users.noreply.github.com> +Udo Liess +VisualMelon +vhoehn +Vsevolod Kukol +Xavier +zur003 +Markus Ebner +Duncan Robertson +LauXjpn +R. Usamentiaga +Dmytro Shaurin +Rustam Sayfutdinov +Konstantin Stukov +jorgectf \ No newline at end of file diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000..ae7bad1 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,2 @@ +next-version: 2.0.0 +branches: {} diff --git a/Icons/OxyPlot.ico b/Icons/OxyPlot.ico new file mode 100644 index 0000000..bc94ef8 Binary files /dev/null and b/Icons/OxyPlot.ico differ diff --git a/Icons/OxyPlot_100.png b/Icons/OxyPlot_100.png new file mode 100644 index 0000000..cfef950 Binary files /dev/null and b/Icons/OxyPlot_100.png differ diff --git a/Icons/OxyPlot_1024.png b/Icons/OxyPlot_1024.png new file mode 100644 index 0000000..e1de425 Binary files /dev/null and b/Icons/OxyPlot_1024.png differ diff --git a/Icons/OxyPlot_114.png b/Icons/OxyPlot_114.png new file mode 100644 index 0000000..994bb2e Binary files /dev/null and b/Icons/OxyPlot_114.png differ diff --git a/Icons/OxyPlot_120.png b/Icons/OxyPlot_120.png new file mode 100644 index 0000000..1020395 Binary files /dev/null and b/Icons/OxyPlot_120.png differ diff --git a/Icons/OxyPlot_128.png b/Icons/OxyPlot_128.png new file mode 100644 index 0000000..e0fa4f3 Binary files /dev/null and b/Icons/OxyPlot_128.png differ diff --git a/Icons/OxyPlot_144.png b/Icons/OxyPlot_144.png new file mode 100644 index 0000000..88c764e Binary files /dev/null and b/Icons/OxyPlot_144.png differ diff --git a/Icons/OxyPlot_150.png b/Icons/OxyPlot_150.png new file mode 100644 index 0000000..2bb6e23 Binary files /dev/null and b/Icons/OxyPlot_150.png differ diff --git a/Icons/OxyPlot_152.png b/Icons/OxyPlot_152.png new file mode 100644 index 0000000..3dbd9fa Binary files /dev/null and b/Icons/OxyPlot_152.png differ diff --git a/Icons/OxyPlot_16.png b/Icons/OxyPlot_16.png new file mode 100644 index 0000000..6f083d0 Binary files /dev/null and b/Icons/OxyPlot_16.png differ diff --git a/Icons/OxyPlot_20.png b/Icons/OxyPlot_20.png new file mode 100644 index 0000000..cd63c67 Binary files /dev/null and b/Icons/OxyPlot_20.png differ diff --git a/Icons/OxyPlot_210.png b/Icons/OxyPlot_210.png new file mode 100644 index 0000000..ffa4c9e Binary files /dev/null and b/Icons/OxyPlot_210.png differ diff --git a/Icons/OxyPlot_24.png b/Icons/OxyPlot_24.png new file mode 100644 index 0000000..cc0e878 Binary files /dev/null and b/Icons/OxyPlot_24.png differ diff --git a/Icons/OxyPlot_256.png b/Icons/OxyPlot_256.png new file mode 100644 index 0000000..a3875f7 Binary files /dev/null and b/Icons/OxyPlot_256.png differ diff --git a/Icons/OxyPlot_270.png b/Icons/OxyPlot_270.png new file mode 100644 index 0000000..d62e9c3 Binary files /dev/null and b/Icons/OxyPlot_270.png differ diff --git a/Icons/OxyPlot_29.png b/Icons/OxyPlot_29.png new file mode 100644 index 0000000..9c59de9 Binary files /dev/null and b/Icons/OxyPlot_29.png differ diff --git a/Icons/OxyPlot_32.png b/Icons/OxyPlot_32.png new file mode 100644 index 0000000..e8c88ed Binary files /dev/null and b/Icons/OxyPlot_32.png differ diff --git a/Icons/OxyPlot_40.png b/Icons/OxyPlot_40.png new file mode 100644 index 0000000..db2dd76 Binary files /dev/null and b/Icons/OxyPlot_40.png differ diff --git a/Icons/OxyPlot_48.png b/Icons/OxyPlot_48.png new file mode 100644 index 0000000..ccaa964 Binary files /dev/null and b/Icons/OxyPlot_48.png differ diff --git a/Icons/OxyPlot_50.png b/Icons/OxyPlot_50.png new file mode 100644 index 0000000..83b35d5 Binary files /dev/null and b/Icons/OxyPlot_50.png differ diff --git a/Icons/OxyPlot_512.png b/Icons/OxyPlot_512.png new file mode 100644 index 0000000..51ce631 Binary files /dev/null and b/Icons/OxyPlot_512.png differ diff --git a/Icons/OxyPlot_57.png b/Icons/OxyPlot_57.png new file mode 100644 index 0000000..12031e1 Binary files /dev/null and b/Icons/OxyPlot_57.png differ diff --git a/Icons/OxyPlot_58.png b/Icons/OxyPlot_58.png new file mode 100644 index 0000000..44fe051 Binary files /dev/null and b/Icons/OxyPlot_58.png differ diff --git a/Icons/OxyPlot_64.png b/Icons/OxyPlot_64.png new file mode 100644 index 0000000..136f55e Binary files /dev/null and b/Icons/OxyPlot_64.png differ diff --git a/Icons/OxyPlot_72.png b/Icons/OxyPlot_72.png new file mode 100644 index 0000000..73f1f09 Binary files /dev/null and b/Icons/OxyPlot_72.png differ diff --git a/Icons/OxyPlot_76.png b/Icons/OxyPlot_76.png new file mode 100644 index 0000000..b95f179 Binary files /dev/null and b/Icons/OxyPlot_76.png differ diff --git a/Icons/OxyPlot_80.png b/Icons/OxyPlot_80.png new file mode 100644 index 0000000..8002ee5 Binary files /dev/null and b/Icons/OxyPlot_80.png differ diff --git a/Icons/OxyPlot_96.png b/Icons/OxyPlot_96.png new file mode 100644 index 0000000..1b4f315 Binary files /dev/null and b/Icons/OxyPlot_96.png differ diff --git a/Icons/favicon.ico b/Icons/favicon.ico new file mode 100644 index 0000000..92c3c98 Binary files /dev/null and b/Icons/favicon.ico differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bba637a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2014 OxyPlot contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..935883c --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +OxyPlot is a cross-platform plotting library for .NET + +![License](https://img.shields.io/badge/license-MIT-red.svg) [![Build status](https://img.shields.io/appveyor/ci/objorke/oxyplot/develop.svg)](https://ci.appveyor.com/project/objorke/oxyplot) + +![Plot](https://oxyplot.github.io/public/images/normal-distributions.png) + + +#### Getting started + +1. Use the NuGet package manager to add a reference to OxyPlot (see details below if you want to use pre-release packages) +2. Add a `PlotView` to your user interface +3. Create a `PlotModel` in your code +4. Bind the `PlotModel` to the `Model` property of your `PlotView` + + +#### Examples + +You can find examples in the `/Source/Examples` folder in the code repository. + + +#### NuGet packages + +The latest pre-release packages are pushed by AppVeyor CI to [myget.org](https://www.myget.org/). To install these packages, set the myget.org package source `https://www.myget.org/F/oxyplot` and remember the "-pre" flag. + +The stable release packages will be pushed to [nuget.org](https://www.nuget.org/packages?q=oxyplot). Note that we have have a lot of old (v2015.\*) and pre-release packages on this feed, and sometimes these show up even if they are unlisted. + +See the [wiki](https://github.com/oxyplot/oxyplot/wiki/NuGet-packages) for information about the available packages. + + +#### More information + +- [Web page](https://oxyplot.github.io) +- [Documentation](https://oxyplot.readthedocs.io/en/latest/) +- [NuGet packages](https://www.nuget.org/packages?q=oxyplot) +- [Stack Overflow](https://stackoverflow.com/questions/tagged/oxyplot) +- [Twitter](https://twitter.com/hashtag/oxyplot) +- [Gitter](https://gitter.im/oxyplot/oxyplot) (chat) + + +#### Contribute + +See [Contributing](.github/CONTRIBUTING.md) for information about how to contribute! diff --git a/Source/.editorconfig b/Source/.editorconfig new file mode 100644 index 0000000..e970a40 --- /dev/null +++ b/Source/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = crlf +insert_final_newline = true +indent_style = space +indent_size = 4 + +[*.cs] + +#### .NET Coding Conventions #### + +# this. and Me. preferences +dotnet_style_qualification_for_event = true:warning +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_property = true:warning diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props new file mode 100644 index 0000000..a4243d5 --- /dev/null +++ b/Source/Directory.Build.props @@ -0,0 +1,12 @@ + + + + + + + Copyright (c) 2014-2022 OxyPlot Contributors + git + https://github.com/oxyplot/oxyplot.git + true + + \ No newline at end of file diff --git a/Source/Directory.Build.targets b/Source/Directory.Build.targets new file mode 100644 index 0000000..31f2c6b --- /dev/null +++ b/Source/Directory.Build.targets @@ -0,0 +1,12 @@ + + + + + + + MIT + https://oxyplot.github.io/ + OxyPlot_128.png + README.md + + diff --git a/Source/Examples/Core.Drawing/Example1/Example1.csproj b/Source/Examples/Core.Drawing/Example1/Example1.csproj new file mode 100644 index 0000000..5301653 --- /dev/null +++ b/Source/Examples/Core.Drawing/Example1/Example1.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + + + + + + + diff --git a/Source/Examples/Core.Drawing/Example1/Program.cs b/Source/Examples/Core.Drawing/Example1/Program.cs new file mode 100644 index 0000000..9bd9331 --- /dev/null +++ b/Source/Examples/Core.Drawing/Example1/Program.cs @@ -0,0 +1,86 @@ +namespace Example1 +{ + using System; + using System.IO; + using System.Linq; + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Core.Drawing; + using OxyPlot.Series; + + class Program + { + static void Main(string[] args) + { + var outputToFile = "test-oxyplot-static-export-file.png"; + var outputExportStreamOOP = "test-oxyplot-ExportToStream.png"; + var outputExportFileOOP = "test-oxyplot-ExportToFile.png"; + + var width = 1024; + var height = 768; + var background = OxyColors.LightGray; + var resolution = 96d; + + var model = BuildPlotModel(); + + // export to file using static methods + PngExporter.Export(model, outputToFile, width, height, resolution); + + // export using the instance methods + using (var stream = new MemoryStream()) + { + var pngExporter = new PngExporter { Width = width, Height = height, Resolution = resolution }; + pngExporter.Export(model, stream); + System.IO.File.WriteAllBytes(outputExportStreamOOP, stream.ToArray()); + } + + var pngExporter2 = new PngExporter { Width = width, Height = height, Resolution = resolution }; + var bitmap = pngExporter2.ExportToBitmap(model); + bitmap.Save(outputExportFileOOP, System.Drawing.Imaging.ImageFormat.Png); + bitmap.Save(Path.ChangeExtension(outputExportFileOOP, ".gif"), System.Drawing.Imaging.ImageFormat.Gif); + } + + private static IPlotModel BuildPlotModel() + { + var rand = new Random(21); + + var model = new PlotModel { Title = "Cake Type Popularity" }; + + var cakePopularity = Enumerable.Range(1, 5).Select(i => rand.NextDouble()).ToArray(); + var sum = cakePopularity.Sum(); + var barItems = cakePopularity.Select(cp => RandomBarItem(cp, sum)).ToArray(); + var barSeries = new BarSeries + { + ItemsSource = barItems, + LabelPlacement = LabelPlacement.Base, + LabelFormatString = "{0:.00}%" + }; + + model.Series.Add(barSeries); + + model.Axes.Add(new CategoryAxis + { + Position = AxisPosition.Left, + Key = "CakeAxis", + ItemsSource = new[] + { + "Apple cake", + "Baumkuchen", + "Bundt Cake", + "Chocolate cake", + "Carrot cake" + } + }); + return model; + } + + private static BarItem RandomBarItem(double cp, double sum) + => new BarItem { Value = cp / sum * 100, Color = RandomColor() }; + + private static OxyColor RandomColor() + { + var r = new Random(); + return OxyColor.FromRgb((byte)r.Next(255), (byte)r.Next(255), (byte)r.Next(255)); + } + } +} diff --git a/Source/Examples/ExampleGenerator/ExampleGenerator.csproj b/Source/Examples/ExampleGenerator/ExampleGenerator.csproj new file mode 100644 index 0000000..06b0f2c --- /dev/null +++ b/Source/Examples/ExampleGenerator/ExampleGenerator.csproj @@ -0,0 +1,22 @@ + + + + net6.0-windows;net7.0-windows + + Exe + + + + + + + + + + + diff --git a/Source/Examples/ExampleGenerator/Program.cs b/Source/Examples/ExampleGenerator/Program.cs new file mode 100644 index 0000000..cf0669a --- /dev/null +++ b/Source/Examples/ExampleGenerator/Program.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using ExampleLibrary; +using OxyPlot; +using OxyPlot.WindowsForms; + +namespace ExampleGenerator +{ + public static class Program + { + private static readonly OxyColor defaultBackground = OxyColor.Parse("#00000000"); + + public static string OutputDirectory { get; set; } + + public static bool DoOptimizePng { get; set; } + + public static bool ExportPng { get; set; } + + public static bool ExportPdf { get; set; } + + public static bool ExportSvg { get; set; } + + public static void Main(string[] args) + { + ExportPng = true; + ExportPdf = true; + ExportSvg = true; + //DoOptimizePng = true; + OutputDirectory = @"."; + if (args.Length > 0) + { + OutputDirectory = args[0]; + } + + var exportTasks = new List(); + + var exampleAssembly = typeof(DocumentationExampleAttribute).Assembly; + foreach (var type in exampleAssembly.GetTypes()) + { + foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) + { + var exportAttribute = method.GetCustomAttribute(); + if (exportAttribute == null) + { + continue; + } + + var model = (PlotModel)method.Invoke(null, null); + var exportTask = Export(model, exportAttribute.Filename.Replace('/', Path.DirectorySeparatorChar)); + exportTasks.Add(exportTask); + } + } + + //Wait for exports to finish + Task.WaitAll(exportTasks.ToArray()); + } + + private static async Task Export(PlotModel model, string name) + { + if (model.Background == defaultBackground) + model.Background = OxyColors.White; + + var fileName = Path.Combine(OutputDirectory, name + ".png"); + var directory = Path.GetDirectoryName(fileName) ?? "."; + + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + if (ExportPng) + { + Console.WriteLine(fileName); + using (var stream = File.Create(fileName)) + { + var exporter = new PngExporter { Width = 600, Height = 400 }; + exporter.Export(model, stream); + } + + if (DoOptimizePng) + await OptimizePng(fileName); + } + + if (ExportPdf) + { + fileName = Path.ChangeExtension(fileName, ".pdf"); + Console.WriteLine(fileName); + using (var stream = File.Create(fileName)) + { + var exporter = new PdfExporter { Width = 600d * 72 / 96, Height = 400d * 72 / 96 }; + exporter.Export(model, stream); + } + } + + if (ExportSvg) + { + fileName = Path.ChangeExtension(fileName, ".svg"); + Console.WriteLine(fileName); + + using (var stream = File.Create(fileName)) + { + using (var exporter = new OxyPlot.WindowsForms.SvgExporter { Width = 600, Height = 400, IsDocument = true }) + { + exporter.Export(model, stream); + } + } + } + } + + + /* PNG Optimization */ + + private static async Task OptimizePng(string pngFile) + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + await OptimizePngWithOptiPNG(pngFile); + } + else + { + await OptimizePngWithTruePNG(pngFile); + } + } + + private static async Task OptimizePngWithTruePNG(string pngFile) + { + // /o max : optimization level + // /nc : don't change ColorType and BitDepth + // /md keep pHYs : keep pHYs metadata + var psi = new ProcessStartInfo("TruePNG.exe", pngFile + " /o max /nc /md keep pHYs") + { + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden + }; + try + { + var p = Process.Start(psi); + await Task.Run(() => p.WaitForExit()); + } + catch (Win32Exception e) + { + throw new Win32Exception( + "Failed to run TruePNG optimization. Please ensure that TruePNG is installed and registered in the PATH variable.", + e); + } + } + + private static async Task OptimizePngWithOptiPNG(string pngFile) + { + var psi = new ProcessStartInfo("optipng", "-o7 " + pngFile) + { + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden + }; + var p = Process.Start(psi); + await Task.Run(() => p.WaitForExit()); + } + } + +} diff --git a/Source/Examples/ExampleLibrary/Annotations/AnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/AnnotationExamples.cs new file mode 100644 index 0000000..e79435b --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/AnnotationExamples.cs @@ -0,0 +1,31 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("Annotations"), Tags("Annotations")] + public static class AnnotationExamples + { + [Example("Tool tips")] + public static PlotModel ToolTips() + { + var model = new PlotModel { Title = "Tool tips" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Annotations.Add(new LineAnnotation { Slope = 0.1, Intercept = 1, Text = "LineAnnotation", ToolTip = "This is a tool tip for the LineAnnotation" }); + model.Annotations.Add(new RectangleAnnotation { MinimumX = 20, MaximumX = 70, MinimumY = 10, MaximumY = 40, TextRotation = 10, Text = "RectangleAnnotation", ToolTip = "This is a tooltip for the RectangleAnnotation", Fill = OxyColor.FromAColor(99, OxyColors.Blue), Stroke = OxyColors.Black, StrokeThickness = 2 }); + model.Annotations.Add(new EllipseAnnotation { X = 20, Y = 60, Width = 20, Height = 15, Text = "EllipseAnnotation", ToolTip = "This is a tool tip for the EllipseAnnotation", TextRotation = 10, Fill = OxyColor.FromAColor(99, OxyColors.Green), Stroke = OxyColors.Black, StrokeThickness = 2 }); + model.Annotations.Add(new PointAnnotation { X = 50, Y = 50, Text = "P1", ToolTip = "This is a tool tip for the PointAnnotation" }); + model.Annotations.Add(new ArrowAnnotation { StartPoint = new DataPoint(8, 4), EndPoint = new DataPoint(0, 0), Color = OxyColors.Green, Text = "ArrowAnnotation", ToolTip = "This is a tool tip for the ArrowAnnotation" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(60, 60), Text = "TextAnnotation", ToolTip = "This is a tool tip for the TextAnnotation" }); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Annotations/ArrowAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/ArrowAnnotationExamples.cs new file mode 100644 index 0000000..0666913 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/ArrowAnnotationExamples.cs @@ -0,0 +1,97 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("ArrowAnnotation"), Tags("Annotations")] + public static class ArrowAnnotationExamples + { + [Example("ArrowAnnotation")] + public static PlotModel ArrowAnnotation() + { + var model = new PlotModel { Title = "ArrowAnnotations" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -40, Maximum = 60 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + model.Annotations.Add( + new ArrowAnnotation + { + StartPoint = new DataPoint(8, 4), + EndPoint = new DataPoint(0, 0), + Color = OxyColors.Green, + Text = "StartPoint and EndPoint" + }); + + model.Annotations.Add( + new ArrowAnnotation + { + ArrowDirection = new ScreenVector(30, 70), + EndPoint = new DataPoint(40, -3), + Color = OxyColors.Blue, + Text = "ArrowDirection and EndPoint" + }); + + model.Annotations.Add( + new ArrowAnnotation + { + ArrowDirection = new ScreenVector(30, -70), + EndPoint = new DataPoint(10, -3), + HeadLength = 14, + HeadWidth = 6, + Veeness = 4, + Color = OxyColors.Red, + Text = "HeadLength = 20, HeadWidth = 10, Veeness = 4" + }); + + return model; + } + + [Example("Rotations")] + public static PlotModel Rotations() + { + var model = new PlotModel { Title = "ArrowAnnotation Rotations" }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Bottom, + Minimum = -5, + Maximum = 45, + MajorGridlineStyle = LineStyle.Solid + }); + + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + StartPosition = 1, + EndPosition = 0, + Minimum = -1, + Maximum = 8, + MajorGridlineStyle = LineStyle.Solid + }); + + for (var i = 0; i < 360; i += 5) + { + var rad = i / 360d * Math.PI * 2; + model.Annotations.Add( + new ArrowAnnotation + { + EndPoint = new DataPoint(i % 45, i / 45), + Text = $"{i}°", + ArrowDirection = new ScreenVector(Math.Cos(rad), Math.Sin(rad)) * 25, + HeadLength = 5 + }); + } + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Annotations/EllipseAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/EllipseAnnotationExamples.cs new file mode 100644 index 0000000..ce93b6c --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/EllipseAnnotationExamples.cs @@ -0,0 +1,30 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("EllipseAnnotation"), Tags("Annotations")] + public static class EllipseAnnotationExamples + { + [Example("EllipseAnnotation")] + public static PlotModel EllipseAnnotation() + { + var model = new PlotModel { Title = "EllipseAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Annotations.Add(new EllipseAnnotation { X = 20, Y = 60, Width = 20, Height = 15, Text = "EllipseAnnotation", TextRotation = 10, Fill = OxyColor.FromAColor(99, OxyColors.Green), Stroke = OxyColors.Black, StrokeThickness = 2 }); + + model.Annotations.Add(new EllipseAnnotation { X = 20, Y = 20, Width = 20, Height = 20, Fill = OxyColor.FromAColor(99, OxyColors.Green), Stroke = OxyColors.Black, StrokeThickness = 2 }); + model.Annotations.Add(new EllipseAnnotation { X = 30, Y = 20, Width = 20, Height = 20, Fill = OxyColor.FromAColor(99, OxyColors.Red), Stroke = OxyColors.Black, StrokeThickness = 2 }); + model.Annotations.Add(new EllipseAnnotation { X = 25, Y = 30, Width = 20, Height = 20, Fill = OxyColor.FromAColor(99, OxyColors.Blue), Stroke = OxyColors.Black, StrokeThickness = 2 }); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Annotations/FunctionAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/FunctionAnnotationExamples.cs new file mode 100644 index 0000000..a554af1 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/FunctionAnnotationExamples.cs @@ -0,0 +1,29 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("FunctionAnnotation"), Tags("Annotations")] + public static class FunctionAnnotationExamples + { + [Example("FunctionAnnotation")] + public static PlotModel FunctionAnnotation() + { + var model = new PlotModel { Title = "FunctionAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + model.Annotations.Add(new FunctionAnnotation { Equation = Math.Sin, StrokeThickness = 2, Color = OxyColor.FromAColor(120, OxyColors.Blue), Text = "f(x)=sin(x)" }); + model.Annotations.Add(new FunctionAnnotation { Equation = y => y * y, StrokeThickness = 2, Color = OxyColor.FromAColor(120, OxyColors.Red), Type = FunctionAnnotationType.EquationY, Text = "f(y)=y^2" }); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Annotations/ImageAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/ImageAnnotationExamples.cs new file mode 100644 index 0000000..c3b9639 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/ImageAnnotationExamples.cs @@ -0,0 +1,275 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Reflection; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("ImageAnnotation"), Tags("Annotations")] + public static class ImageAnnotationExamples + { + [Example("ImageAnnotation")] + public static PlotModel ImageAnnotation() + { + var model = new PlotModel { Title = "ImageAnnotation", PlotMargins = new OxyThickness(60, 4, 4, 60) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + OxyImage image; + var assembly = typeof(ImageAnnotationExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("ExampleLibrary.Resources.OxyPlot.png")) + { + image = new OxyImage(stream); + } + + // Centered in plot area, filling width + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + Opacity = 0.2, + Interpolate = false, + X = new PlotLength(0.5, PlotLengthUnit.RelativeToPlotArea), + Y = new PlotLength(0.5, PlotLengthUnit.RelativeToPlotArea), + Width = new PlotLength(1, PlotLengthUnit.RelativeToPlotArea), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Middle + }); + + // Relative to plot area, inside top/right corner, 120pt wide + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + X = new PlotLength(1, PlotLengthUnit.RelativeToPlotArea), + Y = new PlotLength(0, PlotLengthUnit.RelativeToPlotArea), + Width = new PlotLength(120, PlotLengthUnit.ScreenUnits), + HorizontalAlignment = HorizontalAlignment.Right, + VerticalAlignment = VerticalAlignment.Top + }); + + // Relative to plot area, above top/left corner, 20pt high + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + X = new PlotLength(0, PlotLengthUnit.RelativeToPlotArea), + Y = new PlotLength(0, PlotLengthUnit.RelativeToPlotArea), + OffsetY = new PlotLength(-5, PlotLengthUnit.ScreenUnits), + Height = new PlotLength(20, PlotLengthUnit.ScreenUnits), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Bottom + }); + + // At the point (50,50), 200pt wide + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + X = new PlotLength(50, PlotLengthUnit.Data), + Y = new PlotLength(50, PlotLengthUnit.Data), + Width = new PlotLength(200, PlotLengthUnit.ScreenUnits), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top + }); + + // At the point (50,20), 50 x units wide + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + X = new PlotLength(50, PlotLengthUnit.Data), + Y = new PlotLength(20, PlotLengthUnit.Data), + Width = new PlotLength(50, PlotLengthUnit.Data), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Top + }); + + // Relative to the viewport, centered at the bottom, with offset (could also use bottom vertical alignment) + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + X = new PlotLength(0.5, PlotLengthUnit.RelativeToViewport), + Y = new PlotLength(1, PlotLengthUnit.RelativeToViewport), + OffsetY = new PlotLength(-35, PlotLengthUnit.ScreenUnits), + Height = new PlotLength(30, PlotLengthUnit.ScreenUnits), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Top + }); + + // Changing opacity + for (int y = 0; y < 10; y++) + { + model.Annotations.Add( + new ImageAnnotation + { + ImageSource = image, + Opacity = (y + 1) / 10.0, + X = new PlotLength(10, PlotLengthUnit.Data), + Y = new PlotLength(y * 2, PlotLengthUnit.Data), + Width = new PlotLength(100, PlotLengthUnit.ScreenUnits), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Bottom + }); + } + + return model; + } + + [Example("ImageAnnotation - gradient backgrounds")] + public static PlotModel ImageAnnotationAsBackgroundGradient() + { + // http://en.wikipedia.org/wiki/Chartjunk + var model = new PlotModel { Title = "Using ImageAnnotations to draw a gradient backgrounds", Subtitle = "But do you really want this? This is called 'chartjunk'!", PlotMargins = new OxyThickness(60, 4, 4, 60) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + // create a gradient image of height n + int n = 256; + var imageData1 = new OxyColor[1, n]; + for (int i = 0; i < n; i++) + { + imageData1[0, i] = OxyColor.Interpolate(OxyColors.Blue, OxyColors.Red, i / (n - 1.0)); + } + + var image1 = OxyImage.Create(imageData1, ImageFormat.Png); // png is required for silverlight + + // or create a gradient image of height 2 (requires bitmap interpolation to be supported) + var imageData2 = new OxyColor[1, 2]; + imageData2[0, 0] = OxyColors.Yellow; // top color + imageData2[0, 1] = OxyColors.Gray; // bottom color + + var image2 = OxyImage.Create(imageData2, ImageFormat.Png); // png is required for silverlight + + // gradient filling the viewport + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image2, + Interpolate = true, + Layer = AnnotationLayer.BelowAxes, + X = new PlotLength(0, PlotLengthUnit.RelativeToViewport), + Y = new PlotLength(0, PlotLengthUnit.RelativeToViewport), + Width = new PlotLength(1, PlotLengthUnit.RelativeToViewport), + Height = new PlotLength(1, PlotLengthUnit.RelativeToViewport), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top + }); + + // gradient filling the plot area + model.Annotations.Add(new ImageAnnotation + { + ImageSource = image1, + Interpolate = true, + Layer = AnnotationLayer.BelowAxes, + X = new PlotLength(0, PlotLengthUnit.RelativeToPlotArea), + Y = new PlotLength(0, PlotLengthUnit.RelativeToPlotArea), + Width = new PlotLength(1, PlotLengthUnit.RelativeToPlotArea), + Height = new PlotLength(1, PlotLengthUnit.RelativeToPlotArea), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Top + }); + + // verify that a series is rendered above the gradients + model.Series.Add(new FunctionSeries(Math.Sin, 0, 7, 0.01)); + + return model; + } + + [Example("ImageAnnotation - normal axes")] + public static PlotModel ImageAnnotation_NormalAxes() + { + var model = new PlotModel { Title = "ImageAnnotation - normal axes" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + // create an image + var pixels = new OxyColor[2, 2]; + pixels[0, 0] = OxyColors.Blue; + pixels[1, 0] = OxyColors.Yellow; + pixels[0, 1] = OxyColors.Green; + pixels[1, 1] = OxyColors.Red; + + var image = OxyImage.Create(pixels, ImageFormat.Png); + + model.Annotations.Add( + new ImageAnnotation + { + ImageSource = image, + Interpolate = false, + X = new PlotLength(0, PlotLengthUnit.Data), + Y = new PlotLength(0, PlotLengthUnit.Data), + Width = new PlotLength(80, PlotLengthUnit.Data), + Height = new PlotLength(50, PlotLengthUnit.Data), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Bottom + }); + return model; + } + + [Example("ImageAnnotation - reverse horizontal axis")] + public static PlotModel ImageAnnotation_ReverseHorizontalAxis() + { + var model = new PlotModel { Title = "ImageAnnotation - reverse horizontal axis" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StartPosition = 1, EndPosition = 0 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + // create an image + var pixels = new OxyColor[2, 2]; + pixels[0, 0] = OxyColors.Blue; + pixels[1, 0] = OxyColors.Yellow; + pixels[0, 1] = OxyColors.Green; + pixels[1, 1] = OxyColors.Red; + + var image = OxyImage.Create(pixels, ImageFormat.Png); + + model.Annotations.Add( + new ImageAnnotation + { + ImageSource = image, + Interpolate = false, + X = new PlotLength(100, PlotLengthUnit.Data), + Y = new PlotLength(0, PlotLengthUnit.Data), + Width = new PlotLength(80, PlotLengthUnit.Data), + Height = new PlotLength(50, PlotLengthUnit.Data), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Bottom + }); + return model; + } + + [Example("ImageAnnotation - reverse vertical axis")] + public static PlotModel ImageAnnotation_ReverseVerticalAxis() + { + var model = new PlotModel { Title = "ImageAnnotation - reverse vertical axis" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + + // create an image + var pixels = new OxyColor[2, 2]; + pixels[0, 0] = OxyColors.Blue; + pixels[1, 0] = OxyColors.Yellow; + pixels[0, 1] = OxyColors.Green; + pixels[1, 1] = OxyColors.Red; + + var image = OxyImage.Create(pixels, ImageFormat.Png); + + model.Annotations.Add( + new ImageAnnotation + { + ImageSource = image, + Interpolate = false, + X = new PlotLength(0, PlotLengthUnit.Data), + Y = new PlotLength(100, PlotLengthUnit.Data), + Width = new PlotLength(80, PlotLengthUnit.Data), + Height = new PlotLength(50, PlotLengthUnit.Data), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Bottom + }); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Annotations/LineAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/LineAnnotationExamples.cs new file mode 100644 index 0000000..c7ea3f9 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/LineAnnotationExamples.cs @@ -0,0 +1,188 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("LineAnnotation"), Tags("Annotations")] + public static class LineAnnotationExamples + { + [Example("LineAnnotation on linear axes")] + public static PlotModel LineAnnotationOnLinearAxes() + { + var model = new PlotModel { Title = "LineAnnotation on linear axes" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + model.Annotations.Add( + new LineAnnotation + { + Slope = 0.1, + Intercept = 1, + Text = "First", + BorderBackground = OxyColors.White.ChangeOpacity(0.75), + BorderPadding = new OxyThickness(5) + }); + model.Annotations.Add( + new LineAnnotation + { + Slope = 0.3, + Intercept = 2, + MaximumX = 40, + Color = OxyColors.Red, + Text = "Second", + BorderBackground = OxyColors.White.ChangeOpacity(0.75), + BorderPadding = new OxyThickness(5) + }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Vertical, + X = 4, + MaximumY = 10, + Color = OxyColors.Green, + Text = "Vertical", + BorderBackground = OxyColors.White.ChangeOpacity(0.75), + BorderPadding = new OxyThickness(5) + }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Horizontal, + Y = 2, + MaximumX = 4, + Color = OxyColors.Gold, + Text = "Horizontal", + BorderBackground = OxyColors.White.ChangeOpacity(0.75), + BorderPadding = new OxyThickness(5) + }); + return model; + } + + [Example("LineAnnotation on logarithmic axes")] + public static PlotModel LineAnnotationOnLogarithmicAxes() + { + var model = new PlotModel { Title = "LineAnnotation on logarithmic axes" }; + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom, Minimum = 1, Maximum = 80 }); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left, Minimum = 1, Maximum = 10 }); + model.Annotations.Add(new LineAnnotation { Slope = 0.1, Intercept = 1, Text = "First", TextMargin = 40 }); + model.Annotations.Add( + new LineAnnotation { Slope = 0.3, Intercept = 2, MaximumX = 40, Color = OxyColors.Red, Text = "Second" }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Vertical, + X = 4, + MaximumY = 10, + Color = OxyColors.Green, + Text = "Vertical" + }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Horizontal, + Y = 2, + MaximumX = 4, + Color = OxyColors.Gold, + Text = "Horizontal" + }); + return model; + } + + [Example("LineAnnotation with text orientation specified")] + public static PlotModel LineAnnotationOnLinearAxesWithTextOrientation() + { + var model = new PlotModel { Title = "LineAnnotations", Subtitle = "with TextOrientation specified" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + model.Annotations.Add( + new LineAnnotation + { + Slope = 0.1, + Intercept = 1, + Text = "Horizontal", + TextOrientation = AnnotationTextOrientation.Horizontal, + TextVerticalAlignment = VerticalAlignment.Bottom + }); + model.Annotations.Add( + new LineAnnotation + { + Slope = 0.3, + Intercept = 2, + MaximumX = 40, + Color = OxyColors.Red, + Text = "Vertical", + TextOrientation = AnnotationTextOrientation.Vertical + }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Vertical, + X = 4, + MaximumY = 10, + Color = OxyColors.Green, + Text = "Horizontal (x=4)", + TextPadding = 8, + TextOrientation = AnnotationTextOrientation.Horizontal + }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Vertical, + X = 45, + MaximumY = 10, + Color = OxyColors.Green, + Text = "Horizontal (x=45)", + TextHorizontalAlignment = HorizontalAlignment.Left, + TextPadding = 8, + TextOrientation = AnnotationTextOrientation.Horizontal + }); + model.Annotations.Add( + new LineAnnotation + { + Type = LineAnnotationType.Horizontal, + Y = 2, + MaximumX = 4, + Color = OxyColors.Gold, + Text = "Horizontal", + TextLinePosition = 0.5, + TextOrientation = AnnotationTextOrientation.Horizontal + }); + return model; + } + + [Example("LineAnnotation - ClipByAxis property")] + public static PlotModel LinearAxesMultipleAxes() + { + var model = new PlotModel { Title = "ClipByAxis property", Subtitle = "This property specifies if the annotation should be clipped by the current axes or by the full plot area." }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80, StartPosition = 0, EndPosition = 0.45, TextColor = OxyColors.Red }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10, StartPosition = 0, EndPosition = 0.45, TextColor = OxyColors.Green }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80, StartPosition = 0.55, EndPosition = 1, TextColor = OxyColors.Blue }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10, StartPosition = 0.55, EndPosition = 1, TextColor = OxyColors.Orange }); + + model.Annotations.Add(new LineAnnotation { ClipByYAxis = true, Type = LineAnnotationType.Vertical, X = 0, Color = OxyColors.Green, Text = "Vertical, ClipByAxis = true" }); + model.Annotations.Add(new LineAnnotation { ClipByYAxis = false, Type = LineAnnotationType.Vertical, X = 20, Color = OxyColors.Green, Text = "Vertical, ClipByAxis = false" }); + model.Annotations.Add(new LineAnnotation { ClipByXAxis = true, Type = LineAnnotationType.Horizontal, Y = 2, Color = OxyColors.Gold, Text = "Horizontal, ClipByAxis = true" }); + model.Annotations.Add(new LineAnnotation { ClipByXAxis = false, Type = LineAnnotationType.Horizontal, Y = 8, Color = OxyColors.Gold, Text = "Horizontal, ClipByAxis = false" }); + return model; + } + + [Example("LineAnnotation on reversed axes")] + public static PlotModel ReversedAxes() + { + var model = new PlotModel { Title = "LineAnnotation on reversed axes" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80, StartPosition = 1, EndPosition = 0 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10, StartPosition = 1, EndPosition = 0 }); + model.Annotations.Add(new LineAnnotation { Slope = 0.1, Intercept = 1, Text = "First", TextHorizontalAlignment = HorizontalAlignment.Left }); + model.Annotations.Add(new LineAnnotation { Slope = 0.3, Intercept = 2, MaximumX = 40, Color = OxyColors.Red, Text = "Second", TextHorizontalAlignment = HorizontalAlignment.Left, TextVerticalAlignment = VerticalAlignment.Bottom }); + model.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Vertical, X = 4, MaximumY = 10, Color = OxyColors.Green, Text = "Vertical", TextHorizontalAlignment = HorizontalAlignment.Right }); + model.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Horizontal, Y = 2, MaximumX = 4, Color = OxyColors.Gold, Text = "Horizontal", TextHorizontalAlignment = HorizontalAlignment.Left }); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Annotations/PointAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/PointAnnotationExamples.cs new file mode 100644 index 0000000..bd2471a --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/PointAnnotationExamples.cs @@ -0,0 +1,161 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("PointAnnotation"), Tags("Annotations")] + public static class PointAnnotationExamples + { + [Example("PointAnnotation")] + public static PlotModel PointAnnotation() + { + var model = new PlotModel { Title = "PointAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + model.Annotations.Add(new PointAnnotation { X = 50, Y = 50, Text = "P1" }); + return model; + } + + [Example("PointAnnotation - shapes")] + public static PlotModel PointAnnotationShapes() + { + var model = new PlotModel { Title = "PointAnnotation - shapes" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Maximum = 120 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + // filled + model.Annotations.Add( + new PointAnnotation + { + X = 20, + Y = 60, + Text = "Circle", + Shape = MarkerType.Circle, + Fill = OxyColors.LightGray, + Stroke = OxyColors.DarkGray, + StrokeThickness = 1 + }); + model.Annotations.Add( + new PointAnnotation + { + X = 40, + Y = 60, + Text = "Square", + Shape = MarkerType.Square, + Fill = OxyColors.LightBlue, + Stroke = OxyColors.DarkBlue, + StrokeThickness = 1 + }); + model.Annotations.Add( + new PointAnnotation + { + X = 60, + Y = 60, + Text = "Triangle", + Shape = MarkerType.Triangle, + Fill = OxyColors.IndianRed, + Stroke = OxyColors.Black, + StrokeThickness = 1 + }); + model.Annotations.Add( + new PointAnnotation + { + X = 80, + Y = 60, + Text = "Diamond", + Shape = MarkerType.Diamond, + Fill = OxyColors.ForestGreen, + Stroke = OxyColors.Black, + StrokeThickness = 1 + }); + model.Annotations.Add( + new PointAnnotation + { + X = 100, + Y = 60, + Text = "Custom", + Shape = MarkerType.Custom, + CustomOutline = + new[] + { + new ScreenPoint(-1, -1), new ScreenPoint(1, 1), new ScreenPoint(-1, 1), + new ScreenPoint(1, -1) + }, + Stroke = OxyColors.Black, + Fill = OxyColors.CadetBlue, + StrokeThickness = 1 + }); + + // not filled + model.Annotations.Add( + new PointAnnotation + { + X = 20, + Y = 40, + Text = "Cross", + Shape = MarkerType.Cross, + Stroke = OxyColors.IndianRed, + StrokeThickness = 1 + }); + model.Annotations.Add( + new PointAnnotation + { + X = 40, + Y = 40, + Text = "Plus", + Shape = MarkerType.Plus, + Stroke = OxyColors.Navy, + StrokeThickness = 1 + }); + model.Annotations.Add( + new PointAnnotation + { + X = 60, + Y = 40, + Text = "Star", + Shape = MarkerType.Star, + Stroke = OxyColors.DarkOliveGreen, + StrokeThickness = 1 + }); + + return model; + } + + [Example("PointAnnotation - text alignments")] + public static PlotModel PointAnnotationTextAlignment() + { + var model = new PlotModel { Title = "PointAnnotation - text alignments" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -50, Maximum = 50 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -50, Maximum = 50 }); + + for (var ha = -1; ha <= 1; ha++) + { + var h = (HorizontalAlignment)ha; + for (var va = -1; va <= 1; va++) + { + var v = (VerticalAlignment)va; + model.Annotations.Add( + new PointAnnotation + { + X = ha * 20, + Y = va * 20, + Size = 10, + Text = h + "," + v, + TextHorizontalAlignment = h, + TextVerticalAlignment = v + }); + } + } + + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Annotations/PolygonAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/PolygonAnnotationExamples.cs new file mode 100644 index 0000000..1bb7265 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/PolygonAnnotationExamples.cs @@ -0,0 +1,158 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("PolygonAnnotation"), Tags("Annotations")] + public static class PolygonAnnotationExamples + { + [Example("PolygonAnnotation")] + public static PlotModel PolygonAnnotation() + { + var model = new PlotModel { Title = "PolygonAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + var a1 = new PolygonAnnotation { Text = "Polygon 1" }; + a1.Points.AddRange(new[] { new DataPoint(4, -2), new DataPoint(8, -4), new DataPoint(17, 7), new DataPoint(5, 8), new DataPoint(2, 5) }); + model.Annotations.Add(a1); + return model; + } + + [Example("PolygonAnnotation with custom text position and alignment")] + public static PlotModel PolygonAnnotationTextPosition() + { + var model = new PlotModel { Title = "PolygonAnnotation with fixed text position and alignment" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + var a1 = new PolygonAnnotation { Text = "Polygon 1", TextHorizontalAlignment = HorizontalAlignment.Left, TextVerticalAlignment = VerticalAlignment.Bottom, TextPosition = new DataPoint(4.1, -1.9) }; + a1.Points.AddRange(new[] { new DataPoint(4, -2), new DataPoint(8, -2), new DataPoint(17, 7), new DataPoint(5, 8), new DataPoint(4, 5) }); + model.Annotations.Add(a1); + return model; + } + + [Example("AnnotationLayer property")] + public static PlotModel AnnotationLayerProperty() + { + var model = new PlotModel { Title = "Annotation Layers" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 30, MajorGridlineStyle = LineStyle.Solid, MajorGridlineThickness = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10, MajorGridlineStyle = LineStyle.Solid, MajorGridlineThickness = 1 }); + + var a1 = new PolygonAnnotation + { + Layer = AnnotationLayer.BelowAxes, + Text = "Layer = BelowAxes" + }; + a1.Points.AddRange(new[] + { + new DataPoint(-11, -2), new DataPoint(-7, -4), new DataPoint(-3, 7), new DataPoint(-10, 8), + new DataPoint(-13, 5) + }); + model.Annotations.Add(a1); + var a2 = new PolygonAnnotation + { + Layer = AnnotationLayer.BelowSeries, + Text = "Layer = BelowSeries" + }; + a2.Points.AddRange(new DataPoint[] + { + new DataPoint(4, -2), new DataPoint(8, -4), new DataPoint(12, 7), new DataPoint(5, 8), + new DataPoint(2, 5) + }); + model.Annotations.Add(a2); + var a3 = new PolygonAnnotation { Layer = AnnotationLayer.AboveSeries, Text = "Layer = AboveSeries" }; + a3.Points.AddRange(new[] { new DataPoint(19, -2), new DataPoint(23, -4), new DataPoint(27, 7), new DataPoint(20, 8), new DataPoint(17, 5) }); + model.Annotations.Add(a3); + + model.Series.Add(new FunctionSeries(Math.Sin, -20, 30, 400)); + return model; + } + + [Example("Koch Snowflakes")] + public static PlotModel KockSnowflakes() + { + DataPoint[] triangle(DataPoint centre) + { + return new[] + { + new DataPoint(centre.X, centre.Y + 1), + new DataPoint(centre.X + Math.Sin(Math.PI * 2 / 3), centre.Y + Math.Cos(Math.PI * 2 / 3)), + new DataPoint(centre.X + Math.Sin(Math.PI * 4 / 3), centre.Y + Math.Cos(Math.PI * 4 / 3)), + }; + } + + var model = new PlotModel { Title = "PolygonAnnotation", PlotType = PlotType.Cartesian }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -4, Maximum = 4 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -2, Maximum = 2 }); + + var a1 = new PolygonAnnotation { Text = "MSL = 4", MinimumSegmentLength = 4 }; + a1.Points.AddRange(KochFractal(triangle(new DataPoint(-2, 0)), 8, true, true)); + model.Annotations.Add(a1); + + var a2 = new PolygonAnnotation { Text = "MSL = 2", MinimumSegmentLength = 2 }; + a2.Points.AddRange(KochFractal(triangle(new DataPoint(0, 0)), 8, true, true)); + model.Annotations.Add(a2); + + var a3 = new PolygonAnnotation { Text = "MSL = 1", MinimumSegmentLength = 1 }; + a3.Points.AddRange(KochFractal(triangle(new DataPoint(2, 0)), 8, true, true)); + model.Annotations.Add(a3); + + return model; + } + + public static DataPoint[] KochFractal(DataPoint[] seed, int n, bool clockwise, bool closed) + { + var cos60 = Math.Cos(Math.PI / 3); + var sin60 = Math.Sin(Math.PI / 3); + var cur = seed; + + for (int i = 0; i < n; i++) + { + var next = new DataPoint[closed ? cur.Length * 4 : cur.Length * 4 - 3]; + for (int j = 0; j < (closed ? cur.Length : cur.Length - 1); j++) + { + var p0 = cur[j]; + var p1 = cur[(j + 1) % cur.Length]; + + var dx = (p1.X - p0.X) / 3; + var dy = (p1.Y - p0.Y) / 3; + + double dx2, dy2; + if (clockwise) + { + dx2 = cos60 * dx - sin60 * dy; + dy2 = cos60 * dy + sin60 * dx; + } + else + { + dx2 = cos60 * dx - sin60 * dy; + dy2 = cos60 * dy + sin60 * dx; + } + + next[j * 4] = p0; + next[j * 4 + 1] = new DataPoint(p0.X + dx, p0.Y + dy); + next[j * 4 + 2] = new DataPoint(p0.X + dx + dx2, p0.Y + dy + dy2); + next[j * 4 + 3] = new DataPoint(p0.X + dx * 2, p0.Y + dy * 2); + } + + if (!closed) + { + next[next.Length - 1] = cur[cur.Length - 1]; + } + + cur = next; + } + + return cur; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Annotations/PolylineAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/PolylineAnnotationExamples.cs new file mode 100644 index 0000000..078cc9d --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/PolylineAnnotationExamples.cs @@ -0,0 +1,66 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("PolylineAnnotation"), Tags("Annotations")] + public static class PolylineAnnotationExamples + { + [Example("PolylineAnnotation")] + public static PlotModel PolylineAnnotations() + { + var model = new PlotModel { Title = "PolylineAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 30 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 30 }); + var a1 = new PolylineAnnotation { Text = "Polyline" }; + a1.Points.AddRange(new[] { new DataPoint(0, 10), new DataPoint(5, 5), new DataPoint(20, 1), new DataPoint(30, 20) }); + var a2 = new PolylineAnnotation + { + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + Text = "Smooth Polyline" + }; + a2.Points.AddRange(new[] { new DataPoint(0, 15), new DataPoint(3, 23), new DataPoint(9, 30), new DataPoint(20, 12), new DataPoint(30, 10) }); + model.Annotations.Add(a1); + model.Annotations.Add(a2); + return model; + } + + [Example("Koch Surfaces")] + public static PlotModel KochSurface() + { + DataPoint[] plane(DataPoint centre) + { + return new[] + { + new DataPoint(centre.X - 1, centre.Y), + new DataPoint(centre.X + 1, centre.Y), + }; + } + + var model = new PlotModel { Title = "PolygonAnnotation", PlotType = PlotType.Cartesian }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -2, Maximum = 2 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -2, Maximum = 2 }); + + var a1 = new PolylineAnnotation { Text = "MSL = 4", MinimumSegmentLength = 4, LineStyle = LineStyle.Solid, TextPosition = new DataPoint(0, 1) }; + a1.Points.AddRange(PolygonAnnotationExamples.KochFractal(plane(new DataPoint(0, 1)), 8, true, false)); + model.Annotations.Add(a1); + + var a2 = new PolylineAnnotation { Text = "MSL = 2", MinimumSegmentLength = 2, LineStyle = LineStyle.Solid, TextPosition = new DataPoint(0, 0) }; + a2.Points.AddRange(PolygonAnnotationExamples.KochFractal(plane(new DataPoint(0, 0)), 8, true, false)); + model.Annotations.Add(a2); + + var a3 = new PolylineAnnotation { Text = "MSL = 1", MinimumSegmentLength = 1, LineStyle = LineStyle.Solid, TextPosition = new DataPoint(0, -1) }; + a3.Points.AddRange(PolygonAnnotationExamples.KochFractal(plane(new DataPoint(0, -1)), 8, true, false)); + model.Annotations.Add(a3); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Annotations/RectangleAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/RectangleAnnotationExamples.cs new file mode 100644 index 0000000..129aa5d --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/RectangleAnnotationExamples.cs @@ -0,0 +1,87 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("RectangleAnnotation"), Tags("Annotations")] + public static class RectangleAnnotationExamples + { + [Example("RectangleAnnotation")] + public static PlotModel RectangleAnnotation() + { + var model = new PlotModel { Title = "RectangleAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Annotations.Add(new RectangleAnnotation { MinimumX = 20, MaximumX = 70, MinimumY = 10, MaximumY = 40, TextRotation = 10, Text = "RectangleAnnotation", Fill = OxyColor.FromAColor(99, OxyColors.Blue), Stroke = OxyColors.Black, StrokeThickness = 2 }); + return model; + } + + [Example("RectangleAnnotations - vertical limit")] + public static PlotModel RectangleAnnotationVerticalLimit() + { + var model = new PlotModel { Title = "RectangleAnnotations - vertical limit" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Annotations.Add(new RectangleAnnotation { MaximumY = 89.5, Text = "Valid area", Fill = OxyColor.FromAColor(99, OxyColors.Black) }); + return model; + } + + [Example("RectangleAnnotation - horizontal bands")] + public static PlotModel RectangleAnnotationHorizontals() + { + var model = new PlotModel { Title = "RectangleAnnotation - horizontal bands" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 10 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 87, Maximum = 97, MajorStep = 1, MinorStep = 1 }); + model.Annotations.Add(new RectangleAnnotation { MinimumY = 89.5, MaximumY = 90.8, Text = "Invalid", Fill = OxyColor.FromAColor(99, OxyColors.Red) }); + model.Annotations.Add(new RectangleAnnotation { MinimumY = 90.8, MaximumY = 92.1, Fill = OxyColor.FromAColor(99, OxyColors.Orange) }); + model.Annotations.Add(new RectangleAnnotation { MinimumY = 92.1, MaximumY = 94.6, Fill = OxyColor.FromAColor(99, OxyColors.Yellow) }); + model.Annotations.Add(new RectangleAnnotation { MinimumY = 94.6, MaximumY = 96, Text = "Ok", Fill = OxyColor.FromAColor(99, OxyColors.Green) }); + LineSeries series1; + model.Series.Add(series1 = new LineSeries { Color = OxyColors.Black, StrokeThickness = 6.0, LineJoin = LineJoin.Round }); + series1.Points.Add(new DataPoint(0.5, 90.7)); + series1.Points.Add(new DataPoint(1.5, 91.2)); + series1.Points.Add(new DataPoint(2.5, 91)); + series1.Points.Add(new DataPoint(3.5, 89.5)); + series1.Points.Add(new DataPoint(4.5, 92.5)); + series1.Points.Add(new DataPoint(5.5, 93.1)); + series1.Points.Add(new DataPoint(6.5, 94.5)); + series1.Points.Add(new DataPoint(7.5, 95.5)); + series1.Points.Add(new DataPoint(8.5, 95.7)); + series1.Points.Add(new DataPoint(9.5, 96.0)); + return model; + } + + [Example("RectangleAnnotation - vertical bands")] + public static PlotModel RectangleAnnotationVerticals() + { + var model = new PlotModel { Title = "RectangleAnnotation - vertical bands" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 10 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 87, Maximum = 97, MajorStep = 1, MinorStep = 1 }); + model.Annotations.Add(new RectangleAnnotation { MinimumX = 2.5, MaximumX = 2.8, TextRotation = 90, Text = "Red", Fill = OxyColor.FromAColor(99, OxyColors.Red) }); + model.Annotations.Add(new RectangleAnnotation { MinimumX = 2.8, MaximumX = 6.1, TextRotation = 90, Text = "Orange", Fill = OxyColor.FromAColor(99, OxyColors.Orange) }); + model.Annotations.Add(new RectangleAnnotation { MinimumX = 6.1, MaximumX = 7.6, TextRotation = 90, Text = "Yellow", Fill = OxyColor.FromAColor(99, OxyColors.Yellow) }); + model.Annotations.Add(new RectangleAnnotation { MinimumX = 7.6, MaximumX = 9.7, TextRotation = 270, Text = "Green", Fill = OxyColor.FromAColor(99, OxyColors.Green) }); + LineSeries series1; + model.Series.Add(series1 = new LineSeries { Color = OxyColors.Black, StrokeThickness = 6.0, LineJoin = LineJoin.Round }); + series1.Points.Add(new DataPoint(0.5, 90.7)); + series1.Points.Add(new DataPoint(1.5, 91.2)); + series1.Points.Add(new DataPoint(2.5, 91)); + series1.Points.Add(new DataPoint(3.5, 89.5)); + series1.Points.Add(new DataPoint(4.5, 92.5)); + series1.Points.Add(new DataPoint(5.5, 93.1)); + series1.Points.Add(new DataPoint(6.5, 94.5)); + series1.Points.Add(new DataPoint(7.5, 95.5)); + series1.Points.Add(new DataPoint(8.5, 95.7)); + series1.Points.Add(new DataPoint(9.5, 96.0)); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Annotations/TextAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/TextAnnotationExamples.cs new file mode 100644 index 0000000..af323f2 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/TextAnnotationExamples.cs @@ -0,0 +1,86 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Linq; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("TextAnnotation"), Tags("Annotations")] + public static class TextAnnotationExamples + { + [Example("TextAnnotation")] + public static PlotModel TextAnnotations() + { + var model = new PlotModel { Title = "TextAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -15, Maximum = 25 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -5, Maximum = 18 }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(-6, 0), Text = "Text annotation 1" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(-7, 10), TextRotation = 80, Text = "Text annotation 2" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(2, 2), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Right, TextVerticalAlignment = VerticalAlignment.Top, Text = "Right/Top" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(2, 4), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Right, TextVerticalAlignment = VerticalAlignment.Middle, Text = "Right/Middle" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(2, 6), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Right, TextVerticalAlignment = VerticalAlignment.Bottom, Text = "Right/Bottom" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(10, 2), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Center, TextVerticalAlignment = VerticalAlignment.Top, Text = "Center/Top" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(10, 4), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Center, TextVerticalAlignment = VerticalAlignment.Middle, Text = "Center/Middle" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(10, 6), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Center, TextVerticalAlignment = VerticalAlignment.Bottom, Text = "Center/Bottom" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(18, 2), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Left, TextVerticalAlignment = VerticalAlignment.Top, Text = "Left/Top" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(18, 4), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Left, TextVerticalAlignment = VerticalAlignment.Middle, Text = "Left/Middle" }); + model.Annotations.Add(new TextAnnotation { TextPosition = new DataPoint(18, 6), TextRotation = 20, TextHorizontalAlignment = HorizontalAlignment.Left, TextVerticalAlignment = VerticalAlignment.Bottom, Text = "Left/Bottom" }); + + double d = 0.05; + + Action addPoint = (x, y) => + { + var annotation = new PolygonAnnotation + { + Layer = AnnotationLayer.BelowAxes, + }; + annotation.Points.AddRange(new[] + { + new DataPoint(x - d, y - d), new DataPoint(x + d, y - d), new DataPoint(x + d, y + d), + new DataPoint(x - d, y + d), new DataPoint(x - d, y - d) + }); + model.Annotations.Add(annotation); + }; + + foreach (var a in model.Annotations.ToArray()) + { + var ta = a as TextAnnotation; + if (ta != null) + { + addPoint(ta.TextPosition.X, ta.TextPosition.Y); + } + } + + return model; + } + + [Example("Rotations")] + public static PlotModel Rotations() + { + var model = new PlotModel { Title = "TextAnnotation Rotations" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -5, Maximum = 45 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0, Minimum = -1, Maximum = 8 }); + for (var i = 0; i < 360; i += 5) + { + model.Annotations.Add(new TextAnnotation + { + TextRotation = i, + TextPosition = new DataPoint(i % 45, i / 45), + Text = $"{i}°", + TextVerticalAlignment = VerticalAlignment.Middle, + TextHorizontalAlignment = HorizontalAlignment.Center + }); + } + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Annotations/TileMapAnnotation.cs b/Source/Examples/ExampleLibrary/Annotations/TileMapAnnotation.cs new file mode 100644 index 0000000..e6ea5ea --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/TileMapAnnotation.cs @@ -0,0 +1,407 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides an annotation that shows a tile based map. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Net; + using System.Threading; + + /// + /// Provides an annotation that shows a tile based map. + /// + /// The longitude and latitude range of the map is defined by the range of the x and y axis, respectively. + public class TileMapAnnotation : Annotation + { + /// + /// The image cache. + /// + private readonly Dictionary images = new Dictionary(); + + /// + /// The download queue. + /// + private readonly Queue queue = new Queue(); + + /// + /// The current number of downloads + /// + private int numberOfDownloads; + + /// + /// Initializes a new instance of the class. + /// + public TileMapAnnotation() + { + this.TileSize = 256; + this.MinZoomLevel = 0; + this.MaxZoomLevel = 20; + this.Opacity = 1.0; + this.MaxNumberOfDownloads = 8; + this.UserAgent = "OxyPlotExampleLibrary"; + } + + /// + /// Gets or sets the max number of simultaneous downloads. + /// + /// The max number of downloads. + public int MaxNumberOfDownloads { get; set; } + + /// + /// Gets or sets the URL. + /// + /// The URL. + public string Url { get; set; } + + /// + /// Gets or sets the copyright notice. + /// + /// The copyright notice. + public string CopyrightNotice { get; set; } + + /// + /// Gets or sets the size of the tiles. + /// + /// The size of the tiles. + public int TileSize { get; set; } + + /// + /// Gets or sets the min zoom level. + /// + /// The min zoom level. + public int MinZoomLevel { get; set; } + + /// + /// Gets or sets the max zoom level. + /// + /// The max zoom level. + public int MaxZoomLevel { get; set; } + + /// + /// Gets or sets the opacity. + /// + /// The opacity. + public double Opacity { get; set; } + + /// + /// Gets or sets the user agent used for requests. + /// + public string UserAgent { get; set; } + + /// + /// Renders the annotation on the specified context. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + var lon0 = this.XAxis.ActualMinimum; + var lon1 = this.XAxis.ActualMaximum; + var lat0 = this.YAxis.ActualMinimum; + var lat1 = this.YAxis.ActualMaximum; + + // the desired number of tiles horizontally + double tilesx = this.PlotModel.Width / this.TileSize; + + // calculate the desired zoom level + var n = tilesx / (((lon1 + 180) / 360) - ((lon0 + 180) / 360)); + var zoom = (int)Math.Round(Math.Log(n) / Math.Log(2)); + if (zoom < this.MinZoomLevel) + { + zoom = this.MinZoomLevel; + } + + if (zoom > this.MaxZoomLevel) + { + zoom = this.MaxZoomLevel; + } + + // find tile coordinates for the corners + double x0, y0; + LatLonToTile(lat0, lon0, zoom, out x0, out y0); + double x1, y1; + LatLonToTile(lat1, lon1, zoom, out x1, out y1); + + double xmax = Math.Max(x0, x1); + double xmin = Math.Min(x0, x1); + double ymax = Math.Max(y0, y1); + double ymin = Math.Min(y0, y1); + + var clippingRectangle = this.GetClippingRect(); + + // Add the tiles + for (var x = (int)xmin; x < xmax; x++) + { + for (var y = (int)ymin; y < ymax; y++) + { + string uri = this.GetTileUri(x, y, zoom); + var img = this.GetImage(uri, rc.RendersToScreen); + + if (img == null) + { + continue; + } + + // transform from tile coordinates to lat/lon + double latitude0, latitude1, longitude0, longitude1; + TileToLatLon(x, y, zoom, out latitude0, out longitude0); + TileToLatLon(x + 1, y + 1, zoom, out latitude1, out longitude1); + + // transform from lat/lon to screen coordinates + var s00 = this.Transform(longitude0, latitude0); + var s11 = this.Transform(longitude1, latitude1); + + var r = OxyRect.Create(s00.X, s00.Y, s11.X, s11.Y); + + // draw the image + rc.DrawImage(img, r.Left, r.Top, r.Width, r.Height, this.Opacity, true); + } + } + + // draw the copyright notice + var p = new ScreenPoint(clippingRectangle.Right - 5, clippingRectangle.Bottom - 5); + var textSize = rc.MeasureText(this.CopyrightNotice, this.ActualFont, this.ActualFontSize, this.ActualFontWeight); + rc.DrawRectangle( + new OxyRect(p.X - textSize.Width - 2, p.Y - textSize.Height - 2, textSize.Width + 4, textSize.Height + 4), + OxyColor.FromAColor(200, OxyColors.White), + OxyColors.Undefined, + 0, + this.EdgeRenderingMode); + + rc.DrawText( + p, + this.CopyrightNotice, + OxyColors.Black, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Right, + VerticalAlignment.Bottom); + } + + /// + /// Transforms a position to a tile coordinate. + /// + /// The latitude. + /// The longitude. + /// The zoom. + /// The x. + /// The y. + private static void LatLonToTile(double latitude, double longitude, int zoom, out double x, out double y) + { + // http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + int n = 1 << zoom; + double lat = latitude / 180 * Math.PI; + x = (longitude + 180.0) / 360.0 * n; + y = (1.0 - (Math.Log(Math.Tan(lat) + (1.0 / Math.Cos(lat))) / Math.PI)) / 2.0 * n; + } + + /// + /// Transforms a tile coordinate (x,y) to a position. + /// + /// The x. + /// The y. + /// The zoom. + /// The latitude. + /// The longitude. + private static void TileToLatLon(double x, double y, int zoom, out double latitude, out double longitude) + { + int n = 1 << zoom; + longitude = (x / n * 360.0) - 180.0; + double lat = Math.Atan(Math.Sinh(Math.PI * (1 - (2 * y / n)))); + latitude = lat * 180.0 / Math.PI; + } + + /// + /// Gets the image from the specified uri. + /// + /// The URI. + /// Get the image asynchronously if set to true. The plot model will be invalidated when the image has been downloaded. + /// The image. + /// This method gets the image from cache, or starts an async download. + private OxyImage GetImage(string uri, bool asyncLoading) + { + OxyImage img; + if (this.images.TryGetValue(uri, out img)) + { + return img; + } + + if (!asyncLoading) + { + return this.Download(uri); + } + + lock (this.queue) + { + // 'reserve' an image (otherwise multiple downloads of the same uri may happen) + this.images[uri] = null; + this.queue.Enqueue(uri); + } + + this.BeginDownload(); + return null; + } + + /// + /// Downloads the image from the specified URI. + /// + /// The URI. + /// The image + private OxyImage Download(string uri) + { + OxyImage img = null; + var mre = new ManualResetEvent(false); + var request = (HttpWebRequest)WebRequest.Create(uri); + request.Method = "GET"; + request.BeginGetResponse( + r => + { + try + { + if (request.HaveResponse) + { + var response = request.EndGetResponse(r); + var stream = response.GetResponseStream(); + + var ms = new MemoryStream(); + stream.CopyTo(ms); + var buffer = ms.ToArray(); + + img = new OxyImage(buffer); + this.images[uri] = img; + } + } + catch (Exception e) + { + var ie = e; + while (ie != null) + { + System.Diagnostics.Debug.WriteLine(ie.Message); + ie = ie.InnerException; + } + } + finally + { + mre.Set(); + } + }, + request); + + mre.WaitOne(); + return img; + } + + /// + /// Starts the next download in the queue. + /// + private void BeginDownload() + { + if (this.numberOfDownloads >= this.MaxNumberOfDownloads) + { + return; + } + + string uri = this.queue.Dequeue(); + var request = (HttpWebRequest)WebRequest.Create(uri); + request.Method = "GET"; + +#if NETFRAMEWORK + // unavailable in NET Standard 1.0 + request.UserAgent = this.UserAgent; +#else + // compiles but does not run under NET Framework + request.Headers["User-Agent"] = this.UserAgent; +#endif + + Interlocked.Increment(ref this.numberOfDownloads); + request.BeginGetResponse( + r => + { + Interlocked.Decrement(ref this.numberOfDownloads); + try + { + if (request.HaveResponse) + { + var response = request.EndGetResponse(r); + var stream = response.GetResponseStream(); + this.DownloadCompleted(uri, stream); + } + } + catch (Exception e) + { + var ie = e; + while (ie != null) + { + System.Diagnostics.Debug.WriteLine(ie.Message); + ie = ie.InnerException; + } + } + }, + request); + } + + /// + /// The download completed, set the image. + /// + /// The URI. + /// The result. + private void DownloadCompleted(string uri, Stream result) + { + if (result == null) + { + return; + } + + var ms = new MemoryStream(); + result.CopyTo(ms); + var buffer = ms.ToArray(); + + var img = new OxyImage(buffer); + this.images[uri] = img; + + lock (this.queue) + { + // Clear old items in the queue, new ones will be added when the plot is refreshed + foreach (var queuedUri in this.queue) + { + // Remove the 'reserved' image + this.images.Remove(queuedUri); + } + + this.queue.Clear(); + } + + this.PlotModel.InvalidatePlot(false); + if (this.queue.Count > 0) + { + this.BeginDownload(); + } + } + + /// + /// Gets the tile URI. + /// + /// The tile x. + /// The tile y. + /// The zoom. + /// The uri. + private string GetTileUri(int x, int y, int zoom) + { + string url = this.Url.Replace("{X}", x.ToString(CultureInfo.InvariantCulture)); + url = url.Replace("{Y}", y.ToString(CultureInfo.InvariantCulture)); + return url.Replace("{Z}", zoom.ToString(CultureInfo.InvariantCulture)); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Annotations/TileMapAnnotationExamples.cs b/Source/Examples/ExampleLibrary/Annotations/TileMapAnnotationExamples.cs new file mode 100644 index 0000000..d11d33b --- /dev/null +++ b/Source/Examples/ExampleLibrary/Annotations/TileMapAnnotationExamples.cs @@ -0,0 +1,70 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + + [Examples("TileMapAnnotation"), Tags("Annotations")] + public static class TileMapAnnotationExamples + { + [Example("TileMapAnnotation (openstreetmap.org)", true)] + public static PlotModel TileMapAnnotation2() + { + // See policy document: https://operations.osmfoundation.org/policies/tiles/ + + var model = new PlotModel { Title = "TileMapAnnotation" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 10.4, Maximum = 10.6, Title = "Longitude" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 59.88, Maximum = 59.96, Title = "Latitude" }); + + // Add the tile map annotation + model.Annotations.Add( + new TileMapAnnotation + { + Url = "http://tile.openstreetmap.org/{Z}/{X}/{Y}.png", + CopyrightNotice = "OpenStreetMap", + MaxNumberOfDownloads = 2, + }); + + return model; + } + + [Example("TileMapAnnotation (statkart.no)", true)] + public static PlotModel TileMapAnnotation() + { + var model = new PlotModel { Title = "TileMapAnnotation" }; + + // TODO: scale ratio between the two axes should be fixed (or depending on latitude...) + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 10.4, Maximum = 10.6, Title = "Longitude" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 59.88, Maximum = 59.96, Title = "Latitude" }); + + // Add the tile map annotation + model.Annotations.Add( + new TileMapAnnotation + { + Url = "http://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=toporaster3&zoom={Z}&x={X}&y={Y}", + CopyrightNotice = "Kartgrunnlag: Statens kartverk, Geovekst og kommuner.", + MinZoomLevel = 5, + MaxZoomLevel = 19 + }); + + model.Annotations.Add(new ArrowAnnotation + { + EndPoint = new DataPoint(10.563, 59.888), + ArrowDirection = new ScreenVector(-40, -60), + StrokeThickness = 3, + FontSize = 20, + FontWeight = FontWeights.Bold, + TextColor = OxyColor.FromAColor(160, OxyColors.Magenta), + Color = OxyColor.FromAColor(100, OxyColors.Magenta) + }); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Attributes/DocumentationExampleAttribute.cs b/Source/Examples/ExampleLibrary/Attributes/DocumentationExampleAttribute.cs new file mode 100644 index 0000000..356a257 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Attributes/DocumentationExampleAttribute.cs @@ -0,0 +1,30 @@ +using System; + +namespace ExampleLibrary +{ + /// + /// Marks the model as documentation example to be exported by the ExampleGenerator program. + /// + [AttributeUsage(AttributeTargets.Method)] + public class DocumentationExampleAttribute : Attribute + { + /// + /// + /// + /// The filename of the documentation file without extension. For sub folders, use '/' as path delimiter. + public DocumentationExampleAttribute(string filename) + { + this.Filename = filename; + } + + /// + /// Gets the filename. + /// + /// The filename. + /// + /// For sub folders, use '/' as path delimiter. + /// This is then replaced with the current platforms path separator later in the process. + /// + public string Filename { get; private set; } + } +} diff --git a/Source/Examples/ExampleLibrary/Attributes/ExampleAttribute.cs b/Source/Examples/ExampleLibrary/Attributes/ExampleAttribute.cs new file mode 100644 index 0000000..8a8308f --- /dev/null +++ b/Source/Examples/ExampleLibrary/Attributes/ExampleAttribute.cs @@ -0,0 +1,44 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + /// + /// Specifies the title for an example. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ExampleAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// The title. + /// A value indiciating whether the example should be excluded from automated tests. + public ExampleAttribute(string title = null, bool excludeFromAutomatedTests = false) + { + this.Title = title; + this.ExcludeFromAutomatedTests = excludeFromAutomatedTests; + } + + /// + /// Gets the title. + /// + /// + /// The title. + /// + public string Title { get; private set; } + + /// + /// Gets a value indiciating whether this example should be excluded from automated tests. + /// + /// + /// true if the example should be excluded from automated tests, otherwise false. + /// + public bool ExcludeFromAutomatedTests { get; } + } +} diff --git a/Source/Examples/ExampleLibrary/Attributes/ExamplesAttribute.cs b/Source/Examples/ExampleLibrary/Attributes/ExamplesAttribute.cs new file mode 100644 index 0000000..78841c5 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Attributes/ExamplesAttribute.cs @@ -0,0 +1,34 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + /// + /// Specifies the category for a class containing examples. + /// + [AttributeUsage(AttributeTargets.Class)] + public class ExamplesAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// The category. + public ExamplesAttribute(string category = null) + { + this.Category = category; + } + + /// + /// Gets the category. + /// + /// + /// The category. + /// + public string Category { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Attributes/TagsAttribute.cs b/Source/Examples/ExampleLibrary/Attributes/TagsAttribute.cs new file mode 100644 index 0000000..5d0d1a6 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Attributes/TagsAttribute.cs @@ -0,0 +1,34 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + /// + /// Specifies tags. + /// + [AttributeUsage(AttributeTargets.Class)] + public class TagsAttribute : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// The tags. + public TagsAttribute(params string[] tags) + { + this.Tags = tags; + } + + /// + /// Gets the tags. + /// + /// + /// The tags. + /// + public string[] Tags { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Axes/AxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/AxisExamples.cs new file mode 100644 index 0000000..2a73e07 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/AxisExamples.cs @@ -0,0 +1,1951 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for general axis properties. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Globalization; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + /// + /// Provides examples for general axis properties. + /// + [Examples("Axis examples"), Tags("Axes")] + public class AxisExamples + { + /// + /// Creates an example for the property using . + /// + /// A . + [Example("TickStyle: None")] + public static PlotModel TickStyleNone() + { + return CreateTickStyleExample(TickStyle.None); + } + + [Example("TickStyle: Inside")] + public static PlotModel TickStyleInside() + { + return CreateTickStyleExample(TickStyle.Inside); + } + + [Example("TickStyle: Crossing")] + public static PlotModel TickStyleCrossing() + { + return CreateTickStyleExample(TickStyle.Crossing); + } + + [Example("TickStyle: Outside")] + public static PlotModel TickStyleOutside() + { + return CreateTickStyleExample(TickStyle.Outside); + } + + [Example("TickStyle: Color major and minor ticks differently")] + public static PlotModel TickLineColor() + { + var plotModel1 = new PlotModel { Title = "Color major and minor ticks differently" }; + plotModel1.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + MajorGridlineThickness = 3, + MinorGridlineThickness = 3, + TicklineColor = OxyColors.Blue, + MinorTicklineColor = OxyColors.Gray, + }); + plotModel1.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + MajorGridlineThickness = 3, + MinorGridlineThickness = 3, + TicklineColor = OxyColors.Blue, + MinorTicklineColor = OxyColors.Gray, + }); + return plotModel1; + } + + [Example("GridLinestyle: None (default)")] + public static PlotModel GridlineStyleNone() + { + var plotModel1 = new PlotModel { Title = "No gridlines" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + return plotModel1; + } + + [Example("GridLinestyle: Vertical")] + public static PlotModel GridLinestyleVertical() + { + var plotModel1 = new PlotModel { Title = "Vertical gridlines" }; + plotModel1.Axes.Add(new LinearAxis()); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Bottom + }); + return plotModel1; + } + + [Example("GridLinestyle: Horizontal")] + public static PlotModel GridLinestyleHorizontal() + { + var plotModel1 = new PlotModel { Title = "Horizontal gridlines" }; + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot + }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + return plotModel1; + } + + [Example("GridLinestyle: Horizontal and vertical")] + public static PlotModel GridLinestyleBoth() + { + var plotModel1 = new PlotModel { Title = "Horizontal and vertical gridlines" }; + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot + }); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Bottom + }); + return plotModel1; + } + + [Example("Axis position left/bottom")] + public static PlotModel AxisPositionLeftAndBottom() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Title = "Left" + }); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Bottom, + Title = "Bottom" + }); + return plotModel1; + } + + [Example("Axis position top/right")] + public static PlotModel AxisPositionTopRight() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Right, + Title = "Right" + }); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Top, + Title = "Top" + }); + return plotModel1; + } + + [Example("Axis label angle 45deg")] + public static PlotModel AxisAngle45() + { + var plotModel1 = new PlotModel { PlotMargins = new OxyThickness(60, 40, 60, 30) }; + plotModel1.Axes.Add(new LinearAxis + { + Angle = 45, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Title = "Left" + }); + plotModel1.Axes.Add(new LinearAxis + { + Angle = 45, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Bottom, + Title = "Bottom" + }); + return plotModel1; + } + + [Example("Zero crossing axis")] + public static PlotModel ZeroCrossing() + { + var plotModel1 = new PlotModel + { + Title = "PositionAtZeroCrossing = true", + PlotAreaBorderThickness = new OxyThickness(0), + PlotMargins = new OxyThickness(10, 10, 10, 10) + }; + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 50, + Minimum = -30, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Crossing + }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 70, + Minimum = -50, + Position = AxisPosition.Bottom, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Crossing + }); + return plotModel1; + } + + [Example("Horizontal zero crossing axis")] + public static PlotModel HorizontalZeroCrossing() + { + var plotModel1 = new PlotModel + { + Title = "Bottom axis: PositionAtZeroCrossing = true" + }; + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 50, + Minimum = -30, + Position = AxisPosition.Left, + PositionAtZeroCrossing = false, + }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 70, + Minimum = -50, + Position = AxisPosition.Bottom, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + }); + return plotModel1; + } + + [Example("Vertical zero crossing axis")] + public static PlotModel VerticalZeroCrossing() + { + var plotModel1 = new PlotModel + { + Title = "Left axis: PositionAtZeroCrossing = true" + }; + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 50, + Minimum = -30, + Position = AxisPosition.Left, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 70, + Minimum = -50, + Position = AxisPosition.Bottom, + PositionAtZeroCrossing = false, + }); + return plotModel1; + } + + [Example("Reversed")] + public static PlotModel Reversed() + { + var plotModel1 = new PlotModel { Title = "EndPosition = 0, StartPosition = 1" }; + plotModel1.Axes.Add(new LinearAxis + { + EndPosition = 0, + StartPosition = 1, + Maximum = 50, + Minimum = -30, + Position = AxisPosition.Left + }); + plotModel1.Axes.Add(new LinearAxis + { + EndPosition = 0, + StartPosition = 1, + Maximum = 70, + Minimum = -50, + Position = AxisPosition.Bottom + }); + return plotModel1; + } + + [Example("Sharing Y axis")] + public static PlotModel SharingY() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis + { + EndPosition = 0, + StartPosition = 1, + Maximum = 1.5, + Minimum = -1.5, + Position = AxisPosition.Left + }); + + var x1 = new LinearAxis + { + StartPosition = 0, + EndPosition = 0.45, + Maximum = 7, + Minimum = 0, + Position = AxisPosition.Bottom, + Key = "x1" + }; + plotModel1.Axes.Add(x1); + + var x2 = new LinearAxis + { + StartPosition = 0.55, + EndPosition = 1, + Maximum = 10, + Minimum = 0, + Position = AxisPosition.Bottom, + Key = "x2" + }; + plotModel1.Axes.Add(x2); + + plotModel1.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 1000) { XAxisKey = x1.Key }); + plotModel1.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 1000) { XAxisKey = x2.Key }); + + return plotModel1; + } + + [Example("Four axes")] + public static PlotModel FourAxes() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis { Maximum = 36, Minimum = 0, Title = "km/h" }); + plotModel1.Axes.Add(new LinearAxis { Maximum = 10, Minimum = 0, Position = AxisPosition.Right, Title = "m/s" }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 10, + Minimum = 0, + Position = AxisPosition.Bottom, + Title = "meter" + }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 10000, + Minimum = 0, + Position = AxisPosition.Top, + Title = "millimeter" + }); + return plotModel1; + } + + [Example("Five axes")] + public static PlotModel FiveAxes() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis { EndPosition = 0.25, Maximum = 1, Minimum = -1, Title = "C1" }); + plotModel1.Axes.Add(new LinearAxis + { + EndPosition = 0.5, + Maximum = 1, + Minimum = -1, + Position = AxisPosition.Right, + StartPosition = 0.25, + Title = "C2" + }); + plotModel1.Axes.Add(new LinearAxis + { + EndPosition = 0.75, + Maximum = 1, + Minimum = -1, + StartPosition = 0.5, + Title = "C3" + }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 1, + Minimum = -1, + Position = AxisPosition.Right, + StartPosition = 0.75, + Title = "C4" + }); + plotModel1.Axes.Add(new LinearAxis { Maximum = 100, Minimum = 0, Position = AxisPosition.Bottom, Title = "s" }); + return plotModel1; + } + + [Example("Logarithmic axes")] + public static PlotModel LogarithmicAxes() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LogarithmicAxis + { + Maximum = 1000000, + Minimum = 1, + Title = "Log axis", + UseSuperExponentialFormat = true + }); + plotModel1.Axes.Add(new LogarithmicAxis + { + Maximum = 10000, + Minimum = 0.001, + Position = AxisPosition.Bottom, + Title = "Log axis", + UseSuperExponentialFormat = true + }); + return plotModel1; + } + + [Example("Logarithmic axes Cartesian Plot")] + public static PlotModel CartesianPlotLogarithmicAxes() + { + var plotModel1 = new PlotModel + { + PlotType = PlotType.Cartesian, + }; + plotModel1.Axes.Add(new LogarithmicAxis + { + Maximum = 1000000, + Minimum = 1, + Title = "Log axis", + UseSuperExponentialFormat = true, + MajorGridlineStyle = LineStyle.Solid, + IsPanEnabled = true, + }); + plotModel1.Axes.Add(new LogarithmicAxis + { + Maximum = 10000, + Minimum = 0.001, + Position = AxisPosition.Bottom, + Title = "Log axis", + UseSuperExponentialFormat = true, + MajorGridlineStyle = LineStyle.Solid, + IsPanEnabled = true, + }); + return plotModel1; + } + + [Example("Big numbers")] + public static PlotModel BigNumbers() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis { Maximum = 6E+32, Minimum = -1E+47, Title = "big numbers" }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 3E+50, + Minimum = -1E+40, + Position = AxisPosition.Bottom, + Title = "big numbers" + }); + return plotModel1; + } + + [Example("Big numbers with super exponential format")] + public static PlotModel BigNumbersSuperExponentialFormat() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 6E+32, + Minimum = -1E+47, + Title = "big numbers", + UseSuperExponentialFormat = true + }); + + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 3E+50, + Minimum = -1E+40, + Position = AxisPosition.Bottom, + Title = "big numbers", + UseSuperExponentialFormat = true + }); + return plotModel1; + } + + [Example("Small numbers")] + public static PlotModel SmallNumbers() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new LinearAxis { Maximum = 6E-20, Minimum = -5E-20, Title = "small numbers" }); + plotModel1.Axes.Add(new LinearAxis + { + Maximum = 3E-20, + Minimum = -4E-20, + Position = AxisPosition.Bottom, + Title = "small numbers" + }); + return plotModel1; + } + + [Example("Default padding")] + public static PlotModel Defaultpadding() + { + var plotModel1 = new PlotModel { Title = "Default padding" }; + plotModel1.Axes.Add(new LinearAxis()); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6) + }; + lineSeries1.Points.Add(new DataPoint(10, 4)); + lineSeries1.Points.Add(new DataPoint(12, 7)); + lineSeries1.Points.Add(new DataPoint(16, 3)); + lineSeries1.Points.Add(new DataPoint(20, 9)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("No padding")] + public static PlotModel Nopadding() + { + var plotModel1 = new PlotModel { Title = "No padding" }; + plotModel1.Axes.Add(new LinearAxis { MaximumPadding = 0, MinimumPadding = 0 }); + plotModel1.Axes.Add(new LinearAxis { MaximumPadding = 0, MinimumPadding = 0, Position = AxisPosition.Bottom }); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6) + }; + lineSeries1.Points.Add(new DataPoint(10, 4)); + lineSeries1.Points.Add(new DataPoint(12, 7)); + lineSeries1.Points.Add(new DataPoint(16, 3)); + lineSeries1.Points.Add(new DataPoint(20, 9)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("Padding 10%")] + public static PlotModel Padding() + { + var plotModel1 = new PlotModel { Title = "Padding 10%" }; + plotModel1.Axes.Add(new LinearAxis { MaximumPadding = 0.1, MinimumPadding = 0.1 }); + plotModel1.Axes.Add(new LinearAxis + { + MaximumPadding = 0.1, + MinimumPadding = 0.1, + Position = AxisPosition.Bottom + }); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6) + }; + lineSeries1.Points.Add(new DataPoint(10, 4)); + lineSeries1.Points.Add(new DataPoint(12, 7)); + lineSeries1.Points.Add(new DataPoint(16, 3)); + lineSeries1.Points.Add(new DataPoint(20, 9)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("X-axis MinimumPadding=0.1")] + public static PlotModel XaxisMinimumPadding() + { + var plotModel1 = new PlotModel { Title = "X-axis MinimumPadding=0.1" }; + plotModel1.Axes.Add(new LinearAxis()); + plotModel1.Axes.Add(new LinearAxis { MinimumPadding = 0.1, Position = AxisPosition.Bottom }); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6) + }; + lineSeries1.Points.Add(new DataPoint(10, 4)); + lineSeries1.Points.Add(new DataPoint(12, 7)); + lineSeries1.Points.Add(new DataPoint(16, 3)); + lineSeries1.Points.Add(new DataPoint(20, 9)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("X-axis MaximumPadding=0.1")] + public static PlotModel XaxisMaximumPadding() + { + var plotModel1 = new PlotModel { Title = "X-axis MaximumPadding=0.1" }; + plotModel1.Axes.Add(new LinearAxis()); + plotModel1.Axes.Add(new LinearAxis { MaximumPadding = 0.1, Position = AxisPosition.Bottom }); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6) + }; + lineSeries1.Points.Add(new DataPoint(10, 4)); + lineSeries1.Points.Add(new DataPoint(12, 7)); + lineSeries1.Points.Add(new DataPoint(16, 3)); + lineSeries1.Points.Add(new DataPoint(20, 9)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("AbsoluteMinimum and AbsoluteMaximum")] + public static PlotModel AbsoluteMinimumAndMaximum() + { + var model = new PlotModel { Title = "AbsoluteMinimum=-17, AbsoluteMaximum=63", Subtitle = "Zooming and panning is limited to these values." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Bottom, + Minimum = 0, + Maximum = 50, + AbsoluteMinimum = -17, + AbsoluteMaximum = 63 + }); + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + Maximum = 50, + AbsoluteMinimum = -17, + AbsoluteMaximum = 63 + }); + return model; + } + + [Example("MinimumRange")] + public static PlotModel MinimumRange() + { + var model = new PlotModel { Title = "MinimumRange = 400" }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + MinimumRange = 400 + }); + + return model; + } + + [Example("MaximumRange")] + public static PlotModel MaximumRange() + { + var model = new PlotModel { Title = "MaximumRange = 40" }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + MaximumRange = 40 + }); + + return model; + } + + [Example("Title with unit")] + public static PlotModel TitleWithUnit() + { + var model = new PlotModel { Title = "Axis titles with units" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Speed", Unit = "km/h" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature", Unit = "°C" }); + return model; + } + + [Example("Invisible vertical axis")] + public static PlotModel InvisibleVerticalAxis() + { + var model = new PlotModel { Title = "Invisible vertical axis" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IsAxisVisible = false }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x) / x, -5, 5, 0.1)); + return model; + } + + [Example("Invisible horizontal axis")] + public static PlotModel InvisibleHorizontalAxis() + { + var model = new PlotModel { Title = "Invisible horizontal axis" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, IsAxisVisible = false }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x) * x * x, -5, 5, 0.1)); + return model; + } + + [Example("Zooming disabled")] + public static PlotModel ZoomingDisabled() + { + var model = new PlotModel { Title = "Zooming disabled" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, IsZoomEnabled = false }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IsZoomEnabled = false }); + return model; + } + + [Example("Panning disabled")] + public static PlotModel PanningDisabled() + { + var model = new PlotModel { Title = "Panning disabled" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, IsPanEnabled = false }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IsPanEnabled = false }); + return model; + } + + [Example("Dense intervals")] + public static PlotModel DenseIntervals() + { + var model = new PlotModel { Title = "Dense intervals" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, IntervalLength = 30 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IntervalLength = 20 }); + return model; + } + + [Example("Graph Paper")] + public static PlotModel GraphPaper() + { + var model = new PlotModel { Title = "Graph Paper" }; + var c = OxyColors.DarkBlue; + model.PlotType = PlotType.Cartesian; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Bottom, + Title = "X", + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColor.FromAColor(40, c), + MinorGridlineColor = OxyColor.FromAColor(20, c) + }); + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Title = "Y", + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColor.FromAColor(40, c), + MinorGridlineColor = OxyColor.FromAColor(20, c) + }); + return model; + } + + [Example("Log-Log Paper")] + public static PlotModel LogLogPaper() + { + var model = new PlotModel { Title = "Log-Log Paper" }; + var c = OxyColors.DarkBlue; + model.Axes.Add( + new LogarithmicAxis + { + Position = AxisPosition.Bottom, + Title = "X", + Minimum = 0.1, + Maximum = 1000, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColor.FromAColor(40, c), + MinorGridlineColor = OxyColor.FromAColor(20, c) + }); + model.Axes.Add( + new LogarithmicAxis + { + Position = AxisPosition.Left, + Title = "Y", + Minimum = 0.1, + Maximum = 1000, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColor.FromAColor(40, c), + MinorGridlineColor = OxyColor.FromAColor(20, c) + }); + return model; + } + + [Example("Black background")] + public static PlotModel OnBlack() + { + var model = new PlotModel + { + Title = "Black background", + Background = OxyColors.Black, + TextColor = OxyColors.White, + PlotAreaBorderColor = OxyColors.White + }; + var c = OxyColors.White; + model.PlotType = PlotType.Cartesian; + model.Series.Add(new FunctionSeries(Math.Sin, 0, Math.PI * 2, 1000, "f(x)=sin(x)")); + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Bottom, + Title = "x", + MajorStep = Math.PI / 2, + FormatAsFractions = true, + FractionUnit = Math.PI, + FractionUnitSymbol = "π", + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColor.FromAColor(40, c), + MinorGridlineColor = OxyColor.FromAColor(20, c), + TicklineColor = OxyColors.White + }); + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Title = "f(x)", + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColor.FromAColor(40, c), + MinorGridlineColor = OxyColor.FromAColor(20, c), + TicklineColor = OxyColors.White + }); + return model; + } + + [Example("Background and PlotAreaBackground")] + public static PlotModel Backgrounds() + { + var model = new PlotModel + { + Title = "Background and PlotAreaBackground", + Background = OxyColors.Silver, + PlotAreaBackground = OxyColors.Gray, + PlotAreaBorderColor = OxyColors.Black, + PlotAreaBorderThickness = new OxyThickness(3) + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Current culture")] + public static PlotModel CurrentCulture() + { + var model = new PlotModel { Title = "Current culture" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1 }); + model.Series.Add(new FunctionSeries(Math.Sin, -1, 1, 100)); + return model; + } + + [Example("Invariant culture")] + public static PlotModel InvariantCulture() + { + var model = new PlotModel { Title = "Invariant culture", Culture = CultureInfo.InvariantCulture }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1, MaximumPadding = 1 }); + model.Series.Add(new FunctionSeries(Math.Sin, -1, 1, 100)); + return model; + } + + [Example("Custom culture")] + public static PlotModel CustomCulture() + { + var model = new PlotModel + { + Title = "Custom culture", + Culture = new CultureInfo("en-GB") { NumberFormat = { NumberDecimalSeparator = "·" } } + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1 }); + model.Series.Add(new FunctionSeries(Math.Sin, -1, 1, 100)); + return model; + } + + private static IEnumerable ButterflyCurve(double t0, double t1, int n) + { + // http://en.wikipedia.org/wiki/Butterfly_curve_(transcendental) + double dt = (t1 - t0) / (n - 1); + for (int i = 0; i < n; i++) + { + double t = t0 + dt * i; + double r = (Math.Exp(Math.Cos(t)) - 2 * Math.Cos(4 * t) - Math.Pow(Math.Sin(t / 12), 5)); + double x = Math.Sin(t) * r; + double y = Math.Cos(t) * r; + yield return new DataPoint(x, y); + } + } + + [Example("Long axis titles (clipped at 90%)")] + public static PlotModel LongAxisTitlesClipped90() + { + var longTitle = "Long title 12345678901234567890123456789012345678901234567890123456789012345678901234567890"; + var tooltip = "The tool tip is " + longTitle; + var plotModel1 = new PlotModel { Title = "Long axis titles (clipped at 90%)" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = longTitle, ToolTip = tooltip }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = longTitle, ToolTip = tooltip }); + return plotModel1; + } + + [Example("Long axis titles (clipped at 100%)")] + public static PlotModel LongAxisTitlesClipped100() + { + var longTitle = "Long title 12345678901234567890123456789012345678901234567890123456789012345678901234567890"; + var tooltip = "The tool tip is " + longTitle; + var plotModel1 = new PlotModel { Title = "Long axis titles (clipped at 100%)" }; + plotModel1.Axes.Add( + new LinearAxis { Position = AxisPosition.Left, Title = longTitle, ToolTip = tooltip, TitleClippingLength = 1.0 }); + plotModel1.Axes.Add( + new LinearAxis { Position = AxisPosition.Bottom, Title = longTitle, ToolTip = tooltip, TitleClippingLength = 1.0 }); + return plotModel1; + } + + [Example("Long axis titles (not clipped)")] + public static PlotModel LongAxisTitlesNotClipped() + { + var longTitle = "Long title 12345678901234567890123456789012345678901234567890123456789012345678901234567890"; + var tooltip = "The tool tip is " + longTitle; + var plotModel1 = new PlotModel { Title = "Long axis titles (not clipped)" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = longTitle, ToolTip = tooltip, ClipTitle = false }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = longTitle, ToolTip = tooltip, ClipTitle = false }); + return plotModel1; + } + + [Example("PositionTier")] + public static PlotModel PositionTier() + { + var plotModel1 = new PlotModel(); + var linearAxis1 = new LinearAxis { Maximum = 1, Minimum = -1, Title = "PositionTier=0" }; + plotModel1.Axes.Add(linearAxis1); + var linearAxis2 = new LinearAxis + { + AxislineStyle = LineStyle.Solid, + Maximum = 2, + Minimum = -2, + PositionTier = 1, + Title = "PositionTier=1" + }; + plotModel1.Axes.Add(linearAxis2); + var linearAxis3 = new LinearAxis + { + Maximum = 1, + Minimum = -1, + Position = AxisPosition.Right, + Title = "PositionTier=0" + }; + plotModel1.Axes.Add(linearAxis3); + var linearAxis4 = new LinearAxis + { + AxislineStyle = LineStyle.Solid, + Maximum = 2, + Minimum = -2, + Position = AxisPosition.Right, + PositionTier = 1, + Title = "PositionTier=1" + }; + plotModel1.Axes.Add(linearAxis4); + var linearAxis5 = new LinearAxis + { + Maximum = 1, + Minimum = -1, + Position = AxisPosition.Top, + Title = "PositionTier=0" + }; + plotModel1.Axes.Add(linearAxis5); + var linearAxis6 = new LinearAxis + { + AxislineStyle = LineStyle.Solid, + Maximum = 2, + Minimum = -2, + Position = AxisPosition.Top, + PositionTier = 1, + Title = "PositionTier=1" + }; + plotModel1.Axes.Add(linearAxis6); + var linearAxis7 = new LinearAxis + { + AxislineStyle = LineStyle.Solid, + Maximum = 10, + Minimum = -10, + Position = AxisPosition.Top, + PositionTier = 2, + Title = "PositionTier=2" + }; + plotModel1.Axes.Add(linearAxis7); + var linearAxis8 = new LinearAxis + { + Maximum = 1, + Minimum = -1, + Position = AxisPosition.Bottom, + Title = "PositionTier=0" + }; + plotModel1.Axes.Add(linearAxis8); + var linearAxis9 = new LinearAxis + { + AxislineStyle = LineStyle.Solid, + Maximum = 2, + Minimum = -2, + Position = AxisPosition.Bottom, + PositionTier = 1, + Title = "PositionTier=1" + }; + plotModel1.Axes.Add(linearAxis9); + var linearAxis10 = new LinearAxis + { + AxislineStyle = LineStyle.Solid, + Maximum = 10, + Minimum = -10, + Position = AxisPosition.Bottom, + PositionTier = 2, + Title = "PositionTier=2" + }; + plotModel1.Axes.Add(linearAxis10); + return plotModel1; + } + + [Example("Custom axis title color")] + public static PlotModel TitleColor() + { + var model = new PlotModel { Title = "Custom axis title color" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1, Title = "Bottom axis", TitleColor = OxyColors.Red }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1, Title = "Left axis", TitleColor = OxyColors.Blue }); + model.Series.Add(new FunctionSeries(Math.Sin, -1, 1, 100)); + return model; + } + + [Example("Custom axis label color")] + public static PlotModel LabelColor() + { + var model = new PlotModel { Title = "Custom axis label color" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1, Title = "Bottom axis", TextColor = OxyColors.Red }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1, Title = "Left axis", TextColor = OxyColors.Blue }); + model.Series.Add(new FunctionSeries(Math.Sin, -1, 1, 100)); + return model; + } + + [Example("Angled axis numbers")] + public static PlotModel AngledAxisNumbers() + { + var model = new PlotModel { Title = "Angled axis numbers" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1, Title = "Bottom axis", Angle = 45 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1, Title = "Left axis", Angle = 45 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Top, Minimum = -1, Maximum = 1, Title = "Top axis", Angle = 45 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Minimum = -1, Maximum = 1, Title = "Right axis", Angle = 45 }); + return model; + } + + [Example("Axis distance")] + public static PlotModel AxisDistance() + { + var plotModel = new PlotModel { Title = "AxisDistance = 20" }; + plotModel.Axes.Add(new LinearAxis { AxislineStyle = LineStyle.Solid, AxisDistance = 20, Position = AxisPosition.Bottom }); + plotModel.Axes.Add(new LinearAxis { AxislineStyle = LineStyle.Solid, AxisDistance = 20, Position = AxisPosition.Left }); + plotModel.Axes.Add(new LinearAxis { AxislineStyle = LineStyle.Solid, AxisDistance = 20, Position = AxisPosition.Right }); + plotModel.Axes.Add(new LinearAxis { AxislineStyle = LineStyle.Solid, AxisDistance = 20, Position = AxisPosition.Top }); + return plotModel; + } + + [Example("No axes defined")] + public static PlotModel NoAxesDefined() + { + var plotModel = new PlotModel { Title = "No axes defined", Subtitle = "Bottom and left axes are auto-generated." }; + plotModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 400)); + return plotModel; + } + + /// + /// Shows usage of the property. + /// + /// The for the example. + [Example("LabelFormatter")] + public static PlotModel LabelFormatter() + { + var plotModel = new PlotModel { Title = "LabelFormatter" }; + plotModel.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + Minimum = -10, + Maximum = 10, + LabelFormatter = x => Math.Abs(x) < double.Epsilon ? "ZERO" : x.ToString() + }); + plotModel.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + Maximum = 25, + MajorStep = 1, + MinorStep = 1, + MaximumPadding = 0, + MinimumPadding = 0, + LabelFormatter = y => ((char)(y + 'A')).ToString() + }); + return plotModel; + } + + [Example("Tool tips")] + public static PlotModel ToolTips() + { + var plotModel1 = new PlotModel { Title = "Tool tips" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Left axis", ToolTip = "Tool tip for the left axis" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Bottom axis", ToolTip = "Tool tip for the bottom axis" }); + return plotModel1; + } + + [Example("Sub- and superscript in axis titles")] + public static PlotModel SubSuperscriptInAxisTitles() + { + var plotModel1 = new PlotModel { Title = "Sub- and superscript in axis titles" }; + plotModel1.Axes.Add(new LinearAxis { Title = "Title with^{super}_{sub}script" }); + plotModel1.Axes.Add(new LinearAxis { Title = "Title with^{super}_{sub}script", Position = AxisPosition.Bottom }); + return plotModel1; + } + + [Example("MinimumMajorStep")] + public static PlotModel MinimumMajorStep() + { + var model = new PlotModel + { + Title = "Axes with MinimumMajorStep" + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "MinimuMajorStep = 1", Minimum = 0, Maximum = 2, MinimumMajorStep = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "MinimuMajorStep = 10", Minimum = 0, Maximum = 15, MinimumMajorStep = 10 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Top, Title = "MinimuMajorStep = 0 (default)", Minimum = 0, Maximum = 2 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Title = "MinimuMajorStep = 0 (default)", Minimum = 0, Maximum = 15 }); + return model; + } + + [Example("MinimumMinorStep")] + public static PlotModel MinimumMinorStep() + { + var model = new PlotModel + { + Title = "Axes with MinimumMinorStep" + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "MinimumMinorStep = 1", Minimum = 0, Maximum = 20, MinimumMinorStep = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "MinimumMinorStep = 10", Minimum = 0, Maximum = 150, MinimumMinorStep = 10 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Top, Title = "MinimumMinorStep = 0 (default)", Minimum = 0, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Title = "MinimumMinorStep = 0 (default)", Minimum = 0, Maximum = 150 }); + return model; + } + + [Example("Default AxisTitleDistance")] + public static PlotModel DefaultAxisTitleDistance() + { + var model = new PlotModel + { + Title = "AxisTitleDistance = 4 (default)" + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Bottom", Minimum = 0, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Left", Minimum = 0, Maximum = 150 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Top, Title = "Top", Minimum = 0, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Title = "Right", Minimum = 0, Maximum = 150 }); + return model; + } + + [Example("Custom AxisTitleDistance")] + public static PlotModel CustomAxisTitleDistance() + { + var model = new PlotModel + { + Title = "AxisTitleDistance = 40" + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Bottom", Minimum = 0, Maximum = 20, AxisTitleDistance = 40 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Left", Minimum = 0, Maximum = 150, AxisTitleDistance = 40 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Top, Title = "Top", Minimum = 0, Maximum = 20, AxisTitleDistance = 40 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Right, Title = "Right", Minimum = 0, Maximum = 150, AxisTitleDistance = 40 }); + return model; + } + + [Example("MajorGridlineStyle")] + public static PlotModel MajorGridlineStyle() + { + var pm = new PlotModel { Title = "MajorGridlineStyle and MajorGridlineThickness" }; + pm.Axes.Add(new LinearAxis { MajorGridlineStyle = LineStyle.Solid, MajorGridlineThickness = 10 }); + pm.Axes.Add(new LinearAxis { MajorGridlineStyle = LineStyle.Solid, MajorGridlineThickness = 10, Position = AxisPosition.Bottom }); + return pm; + } + + /// + /// Creates an example with the specified . + /// + /// The tick style. + /// A . + private static PlotModel CreateTickStyleExample(TickStyle tickStyle) + { + var plotModel1 = new PlotModel { Title = "TickStyle = " + tickStyle }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, TickStyle = tickStyle }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, TickStyle = tickStyle }); + return plotModel1; + } + + [Example("Gridlines Cropping: Horizontal and vertical")] + public static PlotModel GridlineCroppingBoth() + { + var plotModel1 = new PlotModel { Title = "Gridline cropping" }; + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + ExtraGridlines = new double[] { 46d }, + ExtraGridlineColor = OxyColors.Red, + StartPosition = 0.1, + EndPosition = 0.4, + CropGridlines = true + }); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + ExtraGridlines = new double[] { 46d }, + ExtraGridlineColor = OxyColors.Red, + StartPosition = 0.6, + EndPosition = 0.9, + CropGridlines = true + }); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Bottom, + ExtraGridlines = new double[] { 46d }, + ExtraGridlineColor = OxyColors.Red, + StartPosition = 0.1, + EndPosition = 0.4, + CropGridlines = true + }); + plotModel1.Axes.Add(new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + Position = AxisPosition.Bottom, + ExtraGridlines = new double[] { 46d }, + ExtraGridlineColor = OxyColors.Red, + StartPosition = 0.6, + EndPosition = 0.9, + CropGridlines = true + }); + return plotModel1; + } + + [Example("Multi vertical axes with lineSeries")] + public static PlotModel MultiVerticalAxes() + { + const string keyAxisY_Temperature = "axisY_Temperature"; + const string keyAxisY_Pressure = "axisY_Pressure"; + const string keyAxisY_Humidity = "axisY_Humidity"; + + var plotModel = new PlotModel() + { + Title = "Multi vertical axes with lineSeries", + }; + + Legend l = new Legend + { + LegendBackground = OxyColors.White + }; + plotModel.Legends.Add(l); + + var axisX_Time = new DateTimeAxis() + { + Title = "Time", + Position = AxisPosition.Bottom, + MajorGridlineStyle = LineStyle.Solid, + FontSize = 13, + }; + plotModel.Axes.Add(axisX_Time); + + LineSeries lineSeriesTemperature = null; + LineSeries lineSeriesPressure = null; + LineSeries lineSeriesHumidity = null; + LinearAxis axisY_Temperature = null; + LinearAxis axisY_Pressure = null; + LinearAxis axisY_Humidity = null; + + //Initialization lineSeries temperature + { + axisY_Temperature = new LinearAxis() + { + Title = "Temperature", + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.None, + PositionTier = 1, + Key = keyAxisY_Temperature, + IsAxisVisible = true, + }; + + lineSeriesTemperature = new LineSeries() + { + Title = "Temperature", + Color = OxyColors.Tomato, + LineStyle = LineStyle.Solid, + MarkerType = MarkerType.Circle, + MarkerSize = 3, + MarkerFill = OxyColors.Red, + YAxisKey = keyAxisY_Temperature, + IsVisible = true, + }; + + plotModel.Axes.Add(axisY_Temperature); + plotModel.Series.Add(lineSeriesTemperature); + } + + // Initialization lineSeries pressure + { + axisY_Pressure = new LinearAxis() + { + Title = "Pressure", + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.None, + PositionTier = 2, + Key = keyAxisY_Pressure, + IsAxisVisible = true, + }; + + lineSeriesPressure = new LineSeries() + { + Title = "Pressure", + Color = OxyColors.Peru, + LineStyle = LineStyle.Solid, + MarkerType = MarkerType.Circle, + MarkerSize = 3, + MarkerFill = OxyColors.Sienna, + YAxisKey = keyAxisY_Pressure, + IsVisible = true, + }; + + plotModel.Axes.Add(axisY_Pressure); + plotModel.Series.Add(lineSeriesPressure); + } + + // Initialization lineSeries humidity + { + axisY_Humidity = new LinearAxis() + { + Title = "Humidity", + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.None, + PositionTier = 3, + Key = keyAxisY_Humidity, + IsAxisVisible = true, + }; + + lineSeriesHumidity = new LineSeries() + { + Title = "Humidity", + Color = OxyColors.LightSkyBlue, + LineStyle = LineStyle.Solid, + MarkerType = MarkerType.Circle, + MarkerSize = 3, + MarkerFill = OxyColors.DeepSkyBlue, + YAxisKey = keyAxisY_Humidity, + IsVisible = true, + }; + + plotModel.Axes.Add(axisY_Humidity); + plotModel.Series.Add(lineSeriesHumidity); + } + + // Add points + { + lineSeriesTemperature.Points.Clear(); + lineSeriesPressure.Points.Clear(); + lineSeriesHumidity.Points.Clear(); + + var timeSpan = TimeSpan.FromSeconds(1); + var time = new DateTime(2018, 09, 10); + int countPoints = 100; + for (int i = 1; i <= countPoints; i++) + { + double temperature = 20 + Math.Sin(i); + double pressure = 760 + 1.5 * Math.Cos(1.5 * i); + double humidity = 50 + 2.0 * Math.Sin(2.0 * i); + + lineSeriesTemperature.Points.Add(DateTimeAxis.CreateDataPoint(time, temperature)); + lineSeriesPressure.Points.Add(DateTimeAxis.CreateDataPoint(time, pressure)); + lineSeriesHumidity.Points.Add(DateTimeAxis.CreateDataPoint(time, humidity)); + + time += timeSpan; + } + + axisY_Temperature.Minimum = 10; + axisY_Temperature.Maximum = 23; + + axisY_Pressure.Minimum = 750; + axisY_Pressure.Maximum = 770; + + axisY_Humidity.Minimum = 47; + axisY_Humidity.Maximum = 60; + } + + return plotModel; + } + + [Example("Auto Margins")] + public static PlotModel AutoMargin() + { + var plotModel = new PlotModel() { Title = "Auto-adjusting plot margins", Subtitle = "When zooming in and out the plot margins should adjust accordingly" }; + plotModel.Axes.Add(new LinearAxis() { Position = AxisPosition.Bottom, Title = "X Axis", TitleFontSize = 16 }); + return plotModel; + } + + [Example("Manual Margins")] + public static PlotModel ManualMargins() + { + var plotModel = new PlotModel() { Title = "Manual Margins", Subtitle = "PlotMargins = 40", PlotMargins = new OxyThickness(40) }; + plotModel.Axes.Add(new LinearAxis() { Position = AxisPosition.Bottom }); + return plotModel; + } + + [Example("Manual Left Margin")] + public static PlotModel ManualLeftMargin() + { + var plotModel = new PlotModel() { Title = "Manual Left Margin", Subtitle = "PlotMargins = 40,NaN,NaN,NaN", PlotMargins = new OxyThickness(40, double.NaN, double.NaN, double.NaN) }; + plotModel.Axes.Add(new LinearAxis() { Position = AxisPosition.Bottom }); + return plotModel; + } + + [Example("Auto Margins - Wide Labels")] + public static PlotModel AutoMarginWideLabels() + { + var plotModel = new PlotModel() { Title = "Auto-adjusting plot margins - wide axis labels", Subtitle = "There should be enough space reserved such that the axis labels always fit in the viewport" }; + plotModel.Axes.Add(GetLongLabelSeries()); + return plotModel; + } + + [Example("Auto Margins - Wide Labels, rotated")] + public static PlotModel AutoMarginWideLabelsRotated() + { + var plotModel = new PlotModel() { Title = "Auto-adjusting plot margins - wide rotated axis labels", Subtitle = "There should be enough space reserved such that the axis labels always fit in the viewport" }; + var axis = GetLongLabelSeries(); + axis.Angle = -90; + plotModel.Axes.Add(axis); + return plotModel; + } + + [Example("Auto Margins - Wide Labels, fixed Range")] + public static PlotModel AutoMarginWideLabelsFixedRange() + { + var plotModel = new PlotModel() { Title = "Auto-adjusting plot margins - wide axis labels, fixed range", Subtitle = "When the axis range is fixed there should be no unnecessary space reserved for axis labels" }; + var axis = GetLongLabelSeries(); + axis.IsPanEnabled = false; + axis.IsZoomEnabled = false; + plotModel.Axes.Add(axis); + return plotModel; + } + + [Example("Auto Margins - Wide Labels, fixed Range 2")] + public static PlotModel AutoMarginWideLabelsFixedRange2() + { + var plotModel = new PlotModel() { Title = "Auto-adjusting plot margins - wide axis labels, fixed range", Subtitle = "The axis labels should exactly fit in the viewport" }; + var axis = GetLongLabelSeries(); + axis.IsPanEnabled = false; + axis.IsZoomEnabled = false; + axis.Minimum = -0.01; + axis.Maximum = 3.01; + plotModel.Axes.Add(axis); + return plotModel; + } + + [Example("Data Margins")] + public static PlotModel MinimumAndMaximumDataMargins() + { + var plot = new PlotModel + { + Title = "Normal distribution", + Subtitle = "Probability density function" + }; + + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + Minimum = 0, + TickStyle = TickStyle.Inside + }); + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + TickStyle = TickStyle.Inside + }); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, 0, 0.2)); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, 0, 1)); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, 0, 5)); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, -2, 0.5)); + + return plot; + } + + [Example("Data Margins with Zero-Crossing")] + public static PlotModel MinimumAndMaximumDataMarginsZeroCrossing() + { + var plot = new PlotModel + { + Title = "Normal distribution", + Subtitle = "Probability density function" + }; + + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + Minimum = 0, + TickStyle = TickStyle.Crossing, + AxislineStyle = LineStyle.Solid, + PositionAtZeroCrossing = true + }); + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + TickStyle = TickStyle.Crossing, + AxislineStyle = LineStyle.Solid, + PositionAtZeroCrossing = true + }); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, 0, 0.2)); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, 0, 1)); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, 0, 5)); + plot.Series.Add(ShowCases.CreateNormalDistributionSeries(-5, 5, -2, 0.5)); + + return plot; + } + + [Example("Data Margins on Log Axis")] + public static PlotModel MinimumAndMaximumDataMarginsLog() + { + var plot = new PlotModel + { + Title = "Exponentials", + }; + + plot.Axes.Add(new LogarithmicAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + TickStyle = TickStyle.Inside + }); + + plot.Axes.Add(new LogarithmicAxis + { + Position = AxisPosition.Left, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + TickStyle = TickStyle.Inside + }); + + for (int i = 1; i <= 5; i++) + { + plot.Series.Add(new FunctionSeries(x => Math.Pow(i, x), 0, 10, 0.01, $"{i}^x")); + } + + return plot; + } + + [Example("Data Margins on Polar Plot")] + public static PlotModel MinimumAndMaximumMarginsPolar() + { + var model = new PlotModel + { + Title = "Spiral", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + + model.Axes.Add(new AngleAxis + { + MajorStep = Math.PI / 4, + MinorStep = Math.PI / 16, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + FormatAsFractions = true, + FractionUnit = Math.PI, + FractionUnitSymbol = "π", + Minimum = 0, + Maximum = 2 * Math.PI + }); + + model.Axes.Add(new MagnitudeAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumDataMargin = 0, + MaximumDataMargin = 20, + }); + + model.Series.Add(new FunctionSeries(t => t, t => t, 0, Math.PI * 6, 0.01)); + return model; + } + + [Example("Axis Margins")] + public static PlotModel AxisOutMargins() + { + var plot = new PlotModel + { + Title = "YAxes are evenly distributed with a constant gap", + PlotAreaBorderThickness = new OxyThickness(0) + }; + + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + AxislineStyle = LineStyle.Solid, + Key = "X" + }); + + int n = 4; + double gap = 10; + + for (int i = 0; i < n; i++) + { + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + StartPosition = i / (double)n, + EndPosition = (i + 1) / (double)n, + MinimumMargin = i / (double)n * gap, + MaximumMargin = (n - i - 1) / (double)n * gap, + AxislineStyle = LineStyle.Solid, + Key = $"Y{i}" + }); ; + + plot.Series.Add(new FunctionSeries(x => Math.Sin(x * (i + 1)), 1, 10, 0.01, $"x^{{{i}}})") { XAxisKey = "X", YAxisKey = $"Y{i}" }); + } + + return plot; + } + + [Example("Axis Margins Clipping")] + public static PlotModel AxisMarginsClipping() + { + var plot = new PlotModel + { + Title = "Axis Margins Clipping", + Subtitle = "Data Points and Visual Elements are clipped outside the Clip Bounds" + }; + + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumMargin = 20, + MaximumMargin = 20, + }); + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumMargin = 20, + MaximumMargin = 20, + }); + + var rnd = new Random(1); + + var scatter = new ScatterSeries() + { + MarkerType = MarkerType.Diamond, + }; + + for (int i = 0; i < 100; i++) + { + scatter.Points.Add(new ScatterPoint(rnd.NextDouble(), rnd.NextDouble())); + } + + plot.Series.Add(scatter); + + return plot; + } + + [Example("Axis Margins on Polar Plot")] + public static PlotModel PolarOuterMargins() + { + var model = new PlotModel + { + Title = "Spiral", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + + model.Axes.Add(new AngleAxis + { + MajorStep = Math.PI / 4, + MinorStep = Math.PI / 16, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + FormatAsFractions = true, + FractionUnit = Math.PI, + FractionUnitSymbol = "π", + Minimum = 0, + Maximum = 2 * Math.PI + }); + + model.Axes.Add(new MagnitudeAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + MinimumPadding = 0, + MaximumPadding = 0, + MinimumMargin = 0, + MaximumMargin = 100, + }); + + model.Series.Add(new FunctionSeries(t => t, t => t, 0, Math.PI * 6, 0.01)); + return model; + } + + [Example("Axis Margins, Data Margins, and Padding")] + public static PlotModel MarginsAndPadding() + { + var plot = new PlotModel + { + Title = "Try resizing the plot", + Subtitle = "ClipMinimum/Maximum are Blue\nActualMinimum/Maximum are Red\nDataMinimum/Maximum are Green" + }; + + var xaxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0.1, + MaximumPadding = 0.1, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + MinimumMargin = 30, + MaximumMargin = 30, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dash, + CropGridlines = true, + }; + + plot.Axes.Add(xaxis); + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + MinimumPadding = 0.1, + MaximumPadding = 0.1, + MinimumDataMargin = 20, + MaximumDataMargin = 20, + MinimumMargin = 30, + MaximumMargin = 30, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dash, + CropGridlines = true, + }; + + plot.Axes.Add(yaxis); + + var rectangle = new LineSeries(); + rectangle.Color = OxyColors.Green; + rectangle.Points.Add(new DataPoint(-5.0, 0.0)); + rectangle.Points.Add(new DataPoint(-5.0, 20.0)); + rectangle.Points.Add(new DataPoint(25.0, 20.0)); + rectangle.Points.Add(new DataPoint(25.0, 0.0)); + rectangle.Points.Add(new DataPoint(-5.0, 0.0)); + plot.Series.Add(rectangle); + + AddAxisMarginAnnotations(plot); + + return plot; + } + + [Example("Axis Margins, Data Margins, and Padding, Asymmetrical")] + public static PlotModel MarginsAndPaddingAsymmetrical() + { + var plot = new PlotModel + { + Title = "Try resizing the plot", + Subtitle = "ClipMinimum/Maximum are Blue\nActualMinimum/Maximum are Red\nDataMinimum/Maximum are Green" + }; + + var xaxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0.1, + MaximumPadding = 0.05, + MinimumDataMargin = 20, + MaximumDataMargin = 10, + MinimumMargin = 30, + MaximumMargin = 15, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dash, + CropGridlines = true, + }; + + plot.Axes.Add(xaxis); + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + MinimumPadding = 0.2, + MaximumPadding = 0.1, + MinimumDataMargin = 40, + MaximumDataMargin = 20, + MinimumMargin = 60, + MaximumMargin = 30, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dash, + CropGridlines = true, + }; + + plot.Axes.Add(yaxis); + + var rectangle = new LineSeries(); + rectangle.Color = OxyColors.Green; + rectangle.Points.Add(new DataPoint(-5.0, 0.0)); + rectangle.Points.Add(new DataPoint(-5.0, 20.0)); + rectangle.Points.Add(new DataPoint(25.0, 20.0)); + rectangle.Points.Add(new DataPoint(25.0, 0.0)); + rectangle.Points.Add(new DataPoint(-5.0, 0.0)); + plot.Series.Add(rectangle); + + AddAxisMarginAnnotations(plot); + + return plot; + } + + [Example("Minimum Major Interval Count")] + public static PlotModel MinimumMajorIntervalCount() + { + var plot = new PlotModel + { + Title = "MinimumMajorIntervalCount = 10", + }; + + var xaxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumMajorIntervalCount = 10, + }; + + plot.Axes.Add(xaxis); + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + MinimumMajorIntervalCount = 10, + }; + + plot.Axes.Add(yaxis); + + return plot; + } + + [Example("Maximum Major Interval Count")] + public static PlotModel MaximumMajorIntervalCount() + { + var plot = new PlotModel + { + Title = "MaximumMajorIntervalCount = 5", + }; + + var xaxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MaximumMajorIntervalCount = 5, + }; + + plot.Axes.Add(xaxis); + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + MaximumMajorIntervalCount = 5, + }; + + plot.Axes.Add(yaxis); + + return plot; + } + + [Example("Minimum and Maximum Major Interval Count")] + public static PlotModel MinimumAndMaximumMajorIntervalCount() + { + var plot = new PlotModel + { + Title = "MinimumMajorIntervalCount = MaximumMajorIntervalCount = 4", + }; + + var xaxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumMajorIntervalCount = 4, + MaximumMajorIntervalCount = 4, + }; + + plot.Axes.Add(xaxis); + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + MinimumMajorIntervalCount = 4, + MaximumMajorIntervalCount = 4, + }; + + plot.Axes.Add(yaxis); + + return plot; + } + + private static CategoryAxis GetLongLabelSeries() + { + var axis = new CategoryAxis() { Position = AxisPosition.Bottom }; + axis.Labels.Add("Label"); + axis.Labels.Add("Long Label"); + axis.Labels.Add("Longer Label"); + axis.Labels.Add("Even Longer Label"); + return axis; + } + + private static void AddAxisMarginAnnotations(PlotModel plot) + { + plot.Annotations.Add(new RenderingCapabilities.DelegateAnnotation(rc => + { + foreach (var axis in plot.Axes) + { + if (axis.IsHorizontal()) + { + var h = axis; + + rc.DrawLine(h.Transform(h.ClipMinimum), 0.0, h.Transform(h.ClipMinimum), plot.Height, new OxyPen(OxyColors.Blue, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + rc.DrawLine(h.Transform(h.ClipMaximum), 0.0, h.Transform(h.ClipMaximum), plot.Height, new OxyPen(OxyColors.Blue, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + + rc.DrawLine(h.Transform(h.ActualMinimum), 0.0, h.Transform(h.ActualMinimum), plot.Height, new OxyPen(OxyColors.Red, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + rc.DrawLine(h.Transform(h.ActualMaximum), 0.0, h.Transform(h.ActualMaximum), plot.Height, new OxyPen(OxyColors.Red, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + + rc.DrawLine(h.Transform(h.DataMinimum), 0.0, h.Transform(h.DataMinimum), plot.Height, new OxyPen(OxyColors.Green, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + rc.DrawLine(h.Transform(h.DataMaximum), 0.0, h.Transform(h.DataMaximum), plot.Height, new OxyPen(OxyColors.Green, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + } + else + { + var v = axis; + + rc.DrawLine(0.0, v.Transform(v.ClipMinimum), plot.Width, v.Transform(v.ClipMinimum), new OxyPen(OxyColors.Blue, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + rc.DrawLine(0.0, v.Transform(v.ClipMaximum), plot.Width, v.Transform(v.ClipMaximum), new OxyPen(OxyColors.Blue, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + + rc.DrawLine(0.0, v.Transform(v.ActualMinimum), plot.Width, v.Transform(v.ActualMinimum), new OxyPen(OxyColors.Red, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + rc.DrawLine(0.0, v.Transform(v.ActualMaximum), plot.Width, v.Transform(v.ActualMaximum), new OxyPen(OxyColors.Red, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + + rc.DrawLine(0.0, v.Transform(v.DataMinimum), plot.Width, v.Transform(v.DataMinimum), new OxyPen(OxyColors.Green, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + rc.DrawLine(0.0, v.Transform(v.DataMaximum), plot.Width, v.Transform(v.DataMaximum), new OxyPen(OxyColors.Green, 1, LineStyle.Dot), EdgeRenderingMode.Automatic); + } + } + })); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/CartesianAxesExamples.cs b/Source/Examples/ExampleLibrary/Axes/CartesianAxesExamples.cs new file mode 100644 index 0000000..92d592d --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/CartesianAxesExamples.cs @@ -0,0 +1,151 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("Cartesian axes"), Tags("Axes")] + public class CartesianAxesExamples + { + [Example("Trigonometric functions")] + public static PlotModel FunctionSeries() + { + var pm = new PlotModel { Title = "Trigonometric functions", PlotType = PlotType.Cartesian }; + pm.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.1, "sin(x)")); + pm.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.1, "cos(x)")); + pm.Series.Add(new FunctionSeries(t => 5 * Math.Cos(t), t => 5 * Math.Sin(t), 0, 2 * Math.PI, 1000, "cos(t),sin(t)")); + return pm; + } + + [Example("Clover")] + public static PlotModel Clover() + { + var plot = new PlotModel { Title = "Parametric function", PlotType = PlotType.Cartesian }; + plot.Series.Add(new FunctionSeries(t => 2 * Math.Cos(2 * t) * Math.Cos(t), t => 2 * Math.Cos(2 * t) * Math.Sin(t), + 0, Math.PI * 2, 1000, "2cos(2t)cos(t) , 2cos(2t)sin(t)")); + return plot; + } + + [Example("AbsoluteMinimum Y")] + public static PlotModel AbsoluteYmin() + { + var plot = new PlotModel { Title = "Y: AbsoluteMinimum = 0", PlotType = PlotType.Cartesian }; + var c = OxyColors.DarkBlue; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis", MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis", AbsoluteMinimum = 0, Minimum = 0, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Series.Add(CreateTestSeries()); + return plot; + } + + [Example("AbsoluteMinimum Y, manual plotmargins")] + public static PlotModel AbsoluteYmin2() + { + var plot = new PlotModel + { + Title = "Y: AbsoluteMinimum = 0", + Subtitle = "AutoAdjustPlotMargins = false", + PlotType = PlotType.Cartesian, + PlotMargins = new OxyThickness(60, 4, 4, 40) + }; + var c = OxyColors.DarkBlue; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis", MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis", AbsoluteMinimum = 0, Minimum = 0, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Series.Add(CreateTestSeries()); + return plot; + } + + [Example("AbsoluteMinimum X/Y")] + public static PlotModel AbsoluteYminXmin() + { + var plot = new PlotModel { Title = "X: AbsoluteMinimum = -10, Y: AbsoluteMinimum = 0", PlotType = PlotType.Cartesian }; + + var c = OxyColors.DarkBlue; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis", AbsoluteMinimum = -10, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis", AbsoluteMinimum = 0, Minimum = 0, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Series.Add(CreateTestSeries()); + return plot; + } + + [Example("AbsoluteMinimum/Maximum Y")] + public static PlotModel AbsoluteYminYmax() + { + var plot = new PlotModel { Title = "Y: AbsoluteMinimum = 0, AbsoluteMaximum = 2", PlotType = PlotType.Cartesian }; + + var c = OxyColors.DarkBlue; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis", MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis", AbsoluteMinimum = 0, Minimum = 0, AbsoluteMaximum = 2, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Series.Add(CreateTestSeries()); + return plot; + } + + [Example("AbsoluteMinimum Y, AbsoluteMinimum/Maximum X")] + public static PlotModel AbsoluteYminXminXmax() + { + var plot = new PlotModel { Title = "Y: AbsoluteMinimum = 0, X: AbsoluteMinimum = -10, AbsoluteMaximum = 10", PlotType = PlotType.Cartesian }; + + var c = OxyColors.DarkBlue; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis", AbsoluteMinimum = -10, AbsoluteMaximum = 10, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis", AbsoluteMinimum = 0, Minimum = 0, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Series.Add(CreateTestSeries()); + + return plot; + } + + [Example("AbsoluteMinimum/Maximum X/Y")] + public static PlotModel AbsoluteYminYmaxXminXmax() + { + var plot = new PlotModel { Title = "Y: AbsoluteMinimum = 0, AbsoluteMaximum = 2, X: AbsoluteMinimum = -10, AbsoluteMaximum = 10", PlotType = PlotType.Cartesian }; + + var c = OxyColors.DarkBlue; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis", AbsoluteMinimum = -10, AbsoluteMaximum = 10, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis", AbsoluteMinimum = 0, Minimum = 0, AbsoluteMaximum = 2, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid, MajorGridlineColor = OxyColor.FromAColor(40, c), MinorGridlineColor = OxyColor.FromAColor(20, c) }); + plot.Series.Add(CreateTestSeries()); + + return plot; + } + + private static OxyPlot.Series.Series CreateTestSeries() + { + var absSerie = new LineSeries(); + + absSerie.Points.Add(new DataPoint(-8.0, 0.0)); + absSerie.Points.Add(new DataPoint(-7.5, 0.1)); + absSerie.Points.Add(new DataPoint(-7.0, 0.2)); + absSerie.Points.Add(new DataPoint(-6.0, 0.4)); + absSerie.Points.Add(new DataPoint(-5.0, 0.5)); + absSerie.Points.Add(new DataPoint(-4.0, 0.6)); + absSerie.Points.Add(new DataPoint(-3.0, 0.7)); + absSerie.Points.Add(new DataPoint(-2.0, 0.8)); + absSerie.Points.Add(new DataPoint(-1.0, 0.9)); + absSerie.Points.Add(new DataPoint(0.0, 1.0)); + absSerie.Points.Add(new DataPoint(1.0, 0.9)); + absSerie.Points.Add(new DataPoint(2.0, 0.8)); + absSerie.Points.Add(new DataPoint(3.0, 0.7)); + absSerie.Points.Add(new DataPoint(4.0, 0.6)); + absSerie.Points.Add(new DataPoint(5.0, 0.5)); + absSerie.Points.Add(new DataPoint(6.0, 0.4)); + absSerie.Points.Add(new DataPoint(7.0, 0.2)); + absSerie.Points.Add(new DataPoint(7.5, 0.1)); + absSerie.Points.Add(new DataPoint(8.0, 0.0)); + + absSerie.Points.Add(DataPoint.Undefined); + + // Plot a square + absSerie.Points.Add(new DataPoint(-0.5, 0.5)); + absSerie.Points.Add(new DataPoint(-0.5, 1.5)); + absSerie.Points.Add(new DataPoint(0.5, 1.5)); + absSerie.Points.Add(new DataPoint(0.5, 0.5)); + absSerie.Points.Add(new DataPoint(-0.5, 0.5)); + + return absSerie; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Axes/CategoryAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/CategoryAxisExamples.cs new file mode 100644 index 0000000..b00e804 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/CategoryAxisExamples.cs @@ -0,0 +1,79 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + + [Examples("CategoryAxis"), Tags("Axes")] + public static class CategoryAxisExamples + { + [Example("Standard")] + public static PlotModel StandardCategoryAxis() + { + var plotModel1 = new PlotModel { Title = "Standard" }; + var catAxis = new CategoryAxis(); + catAxis.Labels.AddRange(new[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }); + plotModel1.Axes.Add(catAxis); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + plotModel1.Axes.Add(linearAxis); + return plotModel1; + } + + [Example("ItemsSource - string[]")] + public static PlotModel ItemsSourceStrings() + { + var model = new PlotModel { Title = "CategoryAxis with string[] as ItemsSource" }; + model.Axes.Add(new CategoryAxis + { + StringFormat = "Item {0}", + ItemsSource = new[] { "A", "B", "C" } + }); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + model.Axes.Add(linearAxis); + return model; + } + + [Example("ItemsSource - int[]")] + public static PlotModel ItemsSourceValues() + { + var model = new PlotModel { Title = "CategoryAxis with int[] as ItemsSource" }; + model.Axes.Add(new CategoryAxis + { + StringFormat = "Item {0}", + ItemsSource = new[] { 10, 100, 123 } + }); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + model.Axes.Add(linearAxis); + return model; + } + + [Example("MajorStep")] + public static PlotModel MajorStepCategoryAxis() + { + var plotModel1 = new PlotModel { Title = "Major Step = 4, IsTickCentered = false" }; + var catAxis = new CategoryAxis { IsTickCentered = false, MajorStep = 4 }; + catAxis.Labels.AddRange(new[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }); + plotModel1.Axes.Add(catAxis); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + plotModel1.Axes.Add(linearAxis); + return plotModel1; + } + + [Example("MajorStep, TickCentered")] + public static PlotModel MajorStepCategoryTickCenteredAxis() + { + var plotModel1 = new PlotModel { Title = "Major Step = 4, IsTickCentered = true" }; + var catAxis = new CategoryAxis { IsTickCentered = true, MajorStep = 4 }; + catAxis.Labels.AddRange(new[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }); + plotModel1.Axes.Add(catAxis); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + plotModel1.Axes.Add(linearAxis); + return plotModel1; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/CategoryColorAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/CategoryColorAxisExamples.cs new file mode 100644 index 0000000..2127362 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/CategoryColorAxisExamples.cs @@ -0,0 +1,49 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("CategoryColorAxis"), Tags("Axes")] + public class CategoryColorAxisExamples + { + [Example("CategoryColorAxis")] + public static PlotModel StandardCategoryColorAxis() + { + var plotModel1 = new PlotModel { Title = "CategoryColorAxis" }; + var catAxis = new CategoryColorAxis { Key = "ccc", Palette = OxyPalettes.BlackWhiteRed(12) }; + catAxis.Labels.AddRange(new[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }); + plotModel1.Axes.Add(catAxis); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + var ss = new ScatterSeries { ColorAxisKey = catAxis.Key }; + ss.Points.Add(new ScatterPoint(0, 0) { Value = 0 }); + ss.Points.Add(new ScatterPoint(3, 0) { Value = 3 }); + plotModel1.Series.Add(ss); + plotModel1.Axes.Add(linearAxis); + return plotModel1; + } + + [Example("Centered ticks, MajorStep = 4")] + public static PlotModel MajorStep4() + { + var plotModel1 = new PlotModel { Title = "Major Step = 4, IsTickCentered = true" }; + var catAxis = new CategoryColorAxis + { + Palette = OxyPalettes.BlackWhiteRed(3), + IsTickCentered = true, + MajorStep = 4 + }; + catAxis.Labels.AddRange(new[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" }); + plotModel1.Axes.Add(catAxis); + var linearAxis = new LinearAxis { Position = AxisPosition.Left }; + plotModel1.Axes.Add(linearAxis); + return plotModel1; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Axes/CustomAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/CustomAxisExamples.cs new file mode 100644 index 0000000..0fd7605 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/CustomAxisExamples.cs @@ -0,0 +1,53 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Axes; + + [Examples("Custom axes"), Tags("Axes")] + public static class CustomAxisExamples + { + public class ArrowAxis : LinearAxis + { + public override void Render(IRenderContext rc, int pass) + { + base.Render(rc, pass); + var points = new List(); + if (this.IsHorizontal()) + { + var xmax = this.Transform(this.ActualMaximum); + points.Add(new ScreenPoint(xmax + 4, this.PlotModel.PlotArea.Bottom - 4)); + points.Add(new ScreenPoint(xmax + 18, this.PlotModel.PlotArea.Bottom)); + points.Add(new ScreenPoint(xmax + 4, this.PlotModel.PlotArea.Bottom + 4)); + //// etc. + } + else + { + var ymax = this.Transform(this.ActualMaximum); + points.Add(new ScreenPoint(this.PlotModel.PlotArea.Left - 4, ymax - 4)); + points.Add(new ScreenPoint(this.PlotModel.PlotArea.Left, ymax - 18)); + points.Add(new ScreenPoint(this.PlotModel.PlotArea.Left + 4, ymax - 4)); + //// etc. + } + + rc.DrawPolygon(points, OxyColors.Black, OxyColors.Undefined, 0, this.EdgeRenderingMode); + } + } + + [Example("ArrowAxis")] + public static PlotModel CustomArrowAxis() + { + var model = new PlotModel { PlotAreaBorderThickness = new OxyThickness(0), PlotMargins = new OxyThickness(60, 60, 60, 60) }; + model.Axes.Add(new ArrowAxis { Position = AxisPosition.Bottom, AxislineStyle = LineStyle.Solid }); + model.Axes.Add(new ArrowAxis { Position = AxisPosition.Left, AxislineStyle = LineStyle.Solid }); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/DateTimeAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/DateTimeAxisExamples.cs new file mode 100644 index 0000000..650b301 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/DateTimeAxisExamples.cs @@ -0,0 +1,248 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Globalization; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("DateTimeAxis"), Tags("Axes")] + public static class DateTimeAxisExamples + { + public class DateValue + { + public DateTime Date { get; set; } + public double Value { get; set; } + } + + [Example("Default StringFormat")] + public static PlotModel DefaultValues() + { + return CreateExample(7, null); + } + + [Example("StringFormat 'MMM dd\\nyyyy'")] + public static PlotModel StringFormat() + { + return CreateExample(7, "MMM dd\nyyyy"); + } + + private static PlotModel CreateExample(int days, string stringFormat) + { + var m = new PlotModel(); + var startTime = new DateTime(2000, 1, 1); + var min = DateTimeAxis.ToDouble(startTime); + var max = min + days; + m.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, Minimum = min, Maximum = max, StringFormat = stringFormat }); + m.Axes.Add(new DateTimeAxis { Position = AxisPosition.Left, Minimum = min, Maximum = max, StringFormat = stringFormat }); + return m; + } + + // [Example("DateTime Minimum bug")] + public static PlotModel Example1() + { + var tmp = new PlotModel { Title = "Test" }; + tmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, TickStyle = TickStyle.Outside }); + var dt = new DateTime(2010, 1, 1); + tmp.Axes.Add(new DateTimeAxis + { + Position = AxisPosition.Bottom, + Minimum = DateTimeAxis.ToDouble(dt), + Maximum = DateTimeAxis.ToDouble(dt.AddDays(1)), + IntervalType = DateTimeIntervalType.Hours, + MajorGridlineStyle = LineStyle.Solid, + Angle = 90, + StringFormat = "HH:mm", + MajorStep = 1.0 / 24 / 2, // 1/24 = 1 hour, 1/24/2 = 30 minutes + IsZoomEnabled = true, + MaximumPadding = 0, + MinimumPadding = 0, + TickStyle = TickStyle.None + }); + + var ls = new LineSeries { Title = "Line1", DataFieldX = "X", DataFieldY = "Y" }; + var ii = new List(); + + for (int i = 0; i < 24; i++) + ii.Add(new Item { X = dt.AddHours(i), Y = i * i }); + ls.ItemsSource = ii; + tmp.Series.Add(ls); + return tmp; + } + + [Example("TimeZone adjustments")] + public static PlotModel DaylightSavingsBreak() + { + var m = new PlotModel(); + + var xa = new DateTimeAxis { Position = AxisPosition.Bottom }; + // TimeZone not available in PCL... + + m.Axes.Add(xa); + m.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var ls = new LineSeries { MarkerType = MarkerType.Circle }; + m.Series.Add(ls); + + // set the origin of the curve to 2013-03-31 00:00:00 (UTC) + var o = new DateTime(2013, 3, 31, 0, 0, 0, DateTimeKind.Utc); + + // add points at 10min intervals + // at 2am the clocks are turned forward 1 hour (W. Europe Standard Time) + for (int i = 0; i < 400; i += 10) + { + var time = o.AddMinutes(i); + ls.Points.Add(DateTimeAxis.CreateDataPoint(time, i)); + } + + return m; + } + + public class Item + { + public DateTime X { get; set; } + public double Y { get; set; } + } + + [Example("DateTime axis")] + public static PlotModel DateTimeaxisPlotModel() + { + var start = new DateTime(2010, 01, 01); + var end = new DateTime(2015, 01, 01); + double increment = 3600 * 24 * 14; + + // Create a random data collection + var r = new Random(13); + var data = new Collection(); + var date = start; + while (date <= end) + { + data.Add(new DateValue { Date = date, Value = r.NextDouble() }); + date = date.AddSeconds(increment); + } + + var plotModel1 = new PlotModel { Title = "DateTime axis" }; + var dateTimeAxis1 = new DateTimeAxis + { + CalendarWeekRule = CalendarWeekRule.FirstFourDayWeek, + FirstDayOfWeek = DayOfWeek.Monday, + Position = AxisPosition.Bottom + }; + plotModel1.Axes.Add(dateTimeAxis1); + var linearAxis1 = new LinearAxis(); + plotModel1.Axes.Add(linearAxis1); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6), + MarkerStroke = OxyColors.ForestGreen, + MarkerType = MarkerType.Plus, + StrokeThickness = 1, + DataFieldX = "Date", + DataFieldY = "Value", + ItemsSource = data + }; + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + public class SunItem + { + public DateTime Day { get; set; } + public TimeSpan Sunrise { get; set; } + public TimeSpan Sunset { get; set; } + } + + private static Collection CreateSunData(int year, double lat, double lon, Func utcToLocalTime) + { + var data = new Collection(); + var day = new DateTime(year, 1, 1); + + while (day.Year == year) + { + var sunrise = Sun.Calculate(day, lat, lon, true, utcToLocalTime); + var sunset = Sun.Calculate(day, lat, lon, false, utcToLocalTime); + data.Add(new SunItem { Day = day, Sunrise = sunrise - day, Sunset = sunset - day }); + day = day.AddDays(1); + } + + return data; + } + + public static bool IsDaylightSaving(DateTime time) + { + // Daylight saving starts last sunday in March and ends last sunday in October + // http://en.wikipedia.org/wiki/Daylight_saving_time + var start = new DateTime(time.Year, 3, 31, 2, 0, 0); + start = start.AddDays(-(int)start.DayOfWeek); + var end = new DateTime(time.Year, 10, 31, 3, 0, 0); + end = end.AddDays(-(int)end.DayOfWeek); + return time >= start && time <= end; + } + + [Example("Sunrise and sunset in Oslo")] + public static PlotModel SunriseandsunsetinOslo() + { + int year = DateTime.Now.Year; + + // Convert UTC time to Western European Time (WET) + Func utcToLocalTime = utc => utc.AddHours(IsDaylightSaving(utc) ? 2 : 1); + + var sunData = CreateSunData(year, 59.91, 10.75, utcToLocalTime); + + var plotModel1 = new PlotModel { Title = "Sunrise and sunset in Oslo", Subtitle = "UTC time" }; + + var dateTimeAxis1 = new DateTimeAxis + { + CalendarWeekRule = CalendarWeekRule.FirstFourDayWeek, + FirstDayOfWeek = DayOfWeek.Monday, + IntervalType = DateTimeIntervalType.Months, + MajorGridlineStyle = LineStyle.Solid, + Position = AxisPosition.Bottom, + StringFormat = "MMM" + }; + plotModel1.Axes.Add(dateTimeAxis1); + var timeSpanAxis1 = new TimeSpanAxis { MajorGridlineStyle = LineStyle.Solid, Maximum = 86400, Minimum = 0, StringFormat = "h:mm" }; + plotModel1.Axes.Add(timeSpanAxis1); + var areaSeries1 = new AreaSeries + { + ItemsSource = sunData, + DataFieldX = "Day", + DataFieldY = "Sunrise", + DataFieldX2 = "Day", + DataFieldY2 = "Sunset", + Fill = OxyColor.FromArgb(128, 255, 255, 0), + Color = OxyColors.Black + }; + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("LabelFormatter")] + public static PlotModel LabelFormatter() + { + var model = new PlotModel { Title = "Using LabelFormatter to format labels by day of week" }; + model.Axes.Add(new DateTimeAxis { LabelFormatter = x => DateTimeAxis.ToDateTime(x).DayOfWeek.ToString().Substring(0, 3) }); + var series = new LineSeries(); + model.Series.Add(series); + for (int i = 0; i < 7; i++) + { + var time = new DateTime(2014, 9, 10).AddDays(i); + double x = DateTimeAxis.ToDouble(time); + double y = Math.Sin(i * i); + series.Points.Add(new DataPoint(x, y)); + } + + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Axes/LinearAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/LinearAxisExamples.cs new file mode 100644 index 0000000..9c45e25 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/LinearAxisExamples.cs @@ -0,0 +1,141 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + + [Examples("LinearAxis"), Tags("Axes")] + public static class LinearAxisExamples + { + [Example("Default StringFormat ('g6')")] + public static PlotModel StringFormat() + { + return CreateExample(1.2345678901234567890e5, 1.2345678901234567890e6, null); + } + + [Example("StringFormat = 'g2'")] + public static PlotModel StringFormatG2() + { + return CreateExample(1.2345678901234567890e5, 1.2345678901234567890e6, "g2"); + } + + [Example("StringFormat = 'g10'")] + public static PlotModel StringFormatG10() + { + return CreateExample(1.2345678901234567890e5, 1.2345678901234567890e6, "g10"); + } + + [Example("StringFormat = 'f2'")] + public static PlotModel StringFormatF2() + { + return CreateExample(1.2345678901234567890e5, 1.2345678901234567890e6, "f2"); + } + + private static PlotModel CreateExample(double min, double max, string stringFormat) + { + var m = new PlotModel(); + m.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = min, Maximum = max, StringFormat = stringFormat }); + m.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = min, Maximum = max, StringFormat = stringFormat }); + return m; + } + + [Example("TickStyle: None")] + public static PlotModel TickStyleNone() + { + return CreateTickStyleModel(TickStyle.None); + } + + [Example("TickStyle: Crossing")] + public static PlotModel TickStyleCrossing() + { + return CreateTickStyleModel(TickStyle.Crossing); + } + + [Example("TickStyle: Inside")] + public static PlotModel TickStyleInside() + { + return CreateTickStyleModel(TickStyle.Inside); + } + + [Example("TickStyle: Outside")] + public static PlotModel TickStyleOutside() + { + return CreateTickStyleModel(TickStyle.Outside); + } + + private static PlotModel CreateTickStyleModel(TickStyle tickStyle) + { + var model = new PlotModel { Title = "TickStyle: " + tickStyle }; + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + TickStyle = tickStyle, + MajorGridlineStyle = LineStyle.None, + MinorGridlineStyle = LineStyle.None, + MaximumPadding = 0, + MinimumPadding = 0 + }); + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + TickStyle = tickStyle, + MajorGridlineStyle = LineStyle.None, + MinorGridlineStyle = LineStyle.None, + MaximumPadding = 0, + MinimumPadding = 0 + }); + return model; + } + + [Example("Gridlines: None")] + public static PlotModel GridlinesNone() + { + return CreateGridlinesModel("None", LineStyle.None, LineStyle.None); + } + + [Example("Gridlines: Horizontal")] + public static PlotModel GridlinesHorizontal() + { + return CreateGridlinesModel("Horizontal", LineStyle.Solid, LineStyle.None); + } + + [Example("Gridlines: Vertical")] + public static PlotModel GridlinesVertical() + { + return CreateGridlinesModel("Vertical", LineStyle.None, LineStyle.Solid); + } + + [Example("Gridlines: Both")] + public static PlotModel GridlinesBoth() + { + return CreateGridlinesModel("Both", LineStyle.Solid, LineStyle.Solid); + } + + private static PlotModel CreateGridlinesModel(string title, LineStyle horizontal, LineStyle vertical) + { + var model = new PlotModel { Title = "Gridlines: " + title }; + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + MajorGridlineStyle = vertical, + MinorGridlineStyle = vertical == LineStyle.Solid ? LineStyle.Dot : LineStyle.None, + MaximumPadding = 0, + MinimumPadding = 0 + }); + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + MajorGridlineStyle = horizontal, + MinorGridlineStyle = horizontal == LineStyle.Solid ? LineStyle.Dot : LineStyle.None, + MaximumPadding = 0, + MinimumPadding = 0 + }); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Axes/LinearColorAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/LinearColorAxisExamples.cs new file mode 100644 index 0000000..909fd52 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/LinearColorAxisExamples.cs @@ -0,0 +1,247 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + + [Examples("LinearColorAxis"), Tags("Axes")] + public class LinearColorAxisExamples + { + [Example("Default palette")] + public static PlotModel DefaultPalette() + { + var model = HeatMapSeriesExamples.CreatePeaks(null, false); + model.Axes.Clear(); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right }); + return model; + } + + [Example("Jet (200 colors) palette")] + public static PlotModel Jet200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(200), false); + } + + [Example("Jet (20 colors) palette")] + public static PlotModel Jet20() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(20), false); + } + + [Example("Hue (400 colors) palette")] + public static PlotModel Hue400() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Hue(400), false); + } + + [Example("Hue distinct (200 colors) palette")] + public static PlotModel HueDistinct200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.HueDistinct(200), false); + } + + [Example("Hue distinct reversed (200 colors) palette")] + public static PlotModel HueDistinctReverse200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.HueDistinct(200).Reverse(), false); + } + + [Example("Hot (200 colors) palette")] + public static PlotModel Hot200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Hot(200), false); + } + + [Example("Hot (64 colors) palette")] + public static PlotModel Hot64() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Hot64, false); + } + + [Example("Hot (30 colors) palette")] + public static PlotModel Hot30() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Hot(30), false); + } + + [Example("Blue-white-red (200 colors) palette")] + public static PlotModel BlueWhiteRed200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.BlueWhiteRed(200), false); + } + + [Example("Blue-white-red (40 colors) palette")] + public static PlotModel BlueWhiteRed40() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.BlueWhiteRed(40), false); + } + + [Example("Black-white-red (500 colors) palette")] + public static PlotModel BlackWhiteRed500() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.BlackWhiteRed(500), false); + } + + [Example("Black-white-red (3 colors) palette")] + public static PlotModel BlackWhiteRed3() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.BlackWhiteRed(3), false); + } + + [Example("Cool (200 colors) palette")] + public static PlotModel Cool200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Cool(200), false); + } + + [Example("Rainbow (200 colors) palette")] + public static PlotModel Rainbow200() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Rainbow(200), false); + } + + [Example("Viridis palette")] + public static PlotModel Viridis() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Viridis(), false); + } + + [Example("Plasma palette")] + public static PlotModel Plasma() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Plasma(), false); + } + + [Example("Magma palette")] + public static PlotModel Magma() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Magma(), false); + } + + [Example("Inferno palette")] + public static PlotModel Inferno() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Inferno(), false); + } + + [Example("Cividis palette")] + public static PlotModel Cividis() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Cividis(), false); + } + + [Example("Viridis (10 colors) palette")] + public static PlotModel Viridis10() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Viridis(10), false); + } + + [Example("Rainbow (7 colors) palette")] + public static PlotModel Rainbow7() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Rainbow(7), false); + } + + [Example("Vertical (6 colors)")] + public static PlotModel Vertical_6() + { + return HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(6), false); + } + + [Example("Vertical reverse (6 colors)")] + public static PlotModel Vertical_Reverse_6() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(6), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.StartPosition = 1; + colorAxis.EndPosition = 0; + return model; + } + + [Example("Horizontal (6 colors)")] + public static PlotModel Horizontal_6() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(6), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.Position = AxisPosition.Top; + return model; + } + + [Example("Horizontal reverse (6 colors)")] + public static PlotModel Horizontal_Reverse_6() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(6), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.Position = AxisPosition.Top; + colorAxis.StartPosition = 1; + colorAxis.EndPosition = 0; + return model; + } + + [Example("RenderAsImage (horizontal)")] + public static PlotModel RenderAsImage_Horizontal() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(1000), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.RenderAsImage = true; + colorAxis.Position = AxisPosition.Top; + return model; + } + + [Example("RenderAsImage (horizontal reversed)")] + public static PlotModel RenderAsImage_Horizontal_Reversed() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(1000), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.RenderAsImage = true; + colorAxis.Position = AxisPosition.Top; + colorAxis.StartPosition = 1; + colorAxis.EndPosition = 0; + return model; + } + + [Example("RenderAsImage (vertical)")] + public static PlotModel RenderAsImage_Vertical() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(1000), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.RenderAsImage = true; + return model; + } + + [Example("RenderAsImage (vertical reversed)")] + public static PlotModel RenderAsImage_Vertical_Reversed() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(1000), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.RenderAsImage = true; + colorAxis.StartPosition = 1; + colorAxis.EndPosition = 0; + return model; + } + + [Example("Short vertical")] + public static PlotModel Vertical_Short() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(600), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.StartPosition = 0.02; + colorAxis.EndPosition = 0.5; + return model; + } + + [Example("Position None")] + public static PlotModel Position_None() + { + var model = HeatMapSeriesExamples.CreatePeaks(OxyPalettes.Jet(600), false); + var colorAxis = (LinearColorAxis)model.Axes[0]; + colorAxis.Position = AxisPosition.None; + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/LogarithmicAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/LogarithmicAxisExamples.cs new file mode 100644 index 0000000..272e802 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/LogarithmicAxisExamples.cs @@ -0,0 +1,176 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("LogarithmicAxis"), Tags("Axes")] + public static class LogarithmicAxisExamples + { + [Example("LogarithmicAxis with default values")] + public static PlotModel DefaultValues() + { + var m = new PlotModel(); + m.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom }); + m.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left}); + return m; + } + + [Example("Amdahl's Law")] + public static PlotModel AmdahlsLaw() + { + var model = new PlotModel { Title = "Amdahl's law" }; + + Legend l = new Legend + { + LegendTitle = "Parallel portion" + }; + model.Legends.Add(l); + + // http://en.wikipedia.org/wiki/Amdahl's_law + Func maxSpeedup = (p, n) => 1.0 / ((1.0 - p) + (double)p / n); + Func createSpeedupCurve = p => + { + // todo: tracker does not work when smoothing = true (too few points interpolated on the left end of the curve) + var ls = new LineSeries { Title = p.ToString("P0") }; + for (int n = 1; n <= 65536; n *= 2) ls.Points.Add(new DataPoint(n, maxSpeedup(p, n))); + return ls; + }; + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom, Title = "Number of processors", Base = 2, MajorGridlineStyle = LineStyle.Solid, TickStyle = TickStyle.None }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 20, MinorStep = 2, MajorStep = 2, Title = "Speedup", StringFormat = "F2", MajorGridlineStyle = LineStyle.Solid, TickStyle = TickStyle.None }); + model.Series.Add(createSpeedupCurve(0.5)); + model.Series.Add(createSpeedupCurve(0.75)); + model.Series.Add(createSpeedupCurve(0.9)); + model.Series.Add(createSpeedupCurve(0.95)); + + return model; + } + + [Example("Richter magnitudes")] + public static PlotModel RichterMagnitudes() + { + // http://en.wikipedia.org/wiki/Richter_magnitude_scale + + var model = new PlotModel + { + Title = "The Richter magnitude scale", + PlotMargins = new OxyThickness(80, 0, 80, 40), + }; + + Legend l = new Legend + { + LegendPlacement = LegendPlacement.Inside, + LegendPosition = LegendPosition.TopCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Richter magnitude scale", MajorGridlineStyle = LineStyle.None, TickStyle = TickStyle.None }); + + var frequencyCurve = new LineSeries + { + Title = "Frequency", + Color = OxyColor.FromUInt32(0xff3c6c9e), + StrokeThickness = 3, + MarkerStroke = OxyColor.FromUInt32(0xff3c6c9e), + MarkerFill = OxyColors.White, + MarkerType = MarkerType.Circle, + MarkerSize = 4, + MarkerStrokeThickness = 3 + }; + + frequencyCurve.Points.Add(new DataPoint(1.5, 8000 * 365 * 100)); + frequencyCurve.Points.Add(new DataPoint(2.5, 1000 * 365 * 100)); + frequencyCurve.Points.Add(new DataPoint(3.5, 49000 * 100)); + frequencyCurve.Points.Add(new DataPoint(4.5, 6200 * 100)); + frequencyCurve.Points.Add(new DataPoint(5.5, 800 * 100)); + frequencyCurve.Points.Add(new DataPoint(6.5, 120 * 100)); + frequencyCurve.Points.Add(new DataPoint(7.5, 18 * 100)); + frequencyCurve.Points.Add(new DataPoint(8.5, 1 * 100)); + frequencyCurve.Points.Add(new DataPoint(9.5, 1.0 / 20 * 100)); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left, Title = "Frequency / 100 yr", UseSuperExponentialFormat = true, MajorGridlineStyle = LineStyle.None, TickStyle = TickStyle.Outside }); + model.Series.Add(frequencyCurve); + + var energyCurve = new LineSeries + { + Title = "Energy", + Color = OxyColor.FromUInt32(0xff9e6c3c), + StrokeThickness = 3, + MarkerStroke = OxyColor.FromUInt32(0xff9e6c3c), + MarkerFill = OxyColors.White, + MarkerType = MarkerType.Circle, + MarkerSize = 4, + MarkerStrokeThickness = 3 + }; + + energyCurve.Points.Add(new DataPoint(1.5, 11e6)); + energyCurve.Points.Add(new DataPoint(2.5, 360e6)); + energyCurve.Points.Add(new DataPoint(3.5, 11e9)); + energyCurve.Points.Add(new DataPoint(4.5, 360e9)); + energyCurve.Points.Add(new DataPoint(5.5, 11e12)); + energyCurve.Points.Add(new DataPoint(6.5, 360e12)); + energyCurve.Points.Add(new DataPoint(7.5, 11e15)); + energyCurve.Points.Add(new DataPoint(8.5, 360e15)); + energyCurve.Points.Add(new DataPoint(9.5, 11e18)); + energyCurve.YAxisKey = "energyAxis"; + + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Right, Title = "Energy / J", Key = "energyAxis", UseSuperExponentialFormat = true, MajorGridlineStyle = LineStyle.None, TickStyle = TickStyle.Outside }); + model.Series.Add(energyCurve); + + return model; + } + + [Example("LogarithmicAxis with AbsoluteMaximum")] + public static PlotModel AbsoluteMaximum() + { + var model = new PlotModel { Title = "AbsoluteMaximum = 1000" }; + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left, Minimum = 0.1, Maximum = 1000, AbsoluteMaximum = 1000 }); + model.Series.Add(new FunctionSeries(Math.Exp, 0, Math.Log(900), 100)); + return model; + } + + [Example("LogarithmicAxis with AxisChanged event handler")] + public static PlotModel AxisChangedEventHAndler() + { + var model = new PlotModel { Title = "AxisChanged event handler" }; + var logAxis = new LogarithmicAxis { Position = AxisPosition.Left, Minimum = 0.1, Maximum = 1000 }; + int n = 0; + logAxis.AxisChanged += (s, e) => { model.Subtitle = "Changed " + (n++) + " times. ActualMaximum=" + logAxis.ActualMaximum; }; + model.Axes.Add(logAxis); + model.Series.Add(new FunctionSeries(Math.Exp, 0, Math.Log(900), 100)); + return model; + } + + [Example("Negative values")] + public static PlotModel NegativeValues() + { + var model = new PlotModel { Title = "LogarithmicAxis", Subtitle = "LineSeries with negative values" }; + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Series.Add(new FunctionSeries(Math.Sin, 0, 40, 1000)); + return model; + } + + [Example("Tick calculation")] + public static PlotModel TickCalculation() + { + var model = new PlotModel { Title = "Tick calculation for different bases" }; + model.Axes.Add(new LogarithmicAxis { Title = "Base 10", Position = AxisPosition.Left, Minimum = 20, Maximum = 20000, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid }); + model.Axes.Add(new LogarithmicAxis { Title = "Base 7", Position = AxisPosition.Bottom, Base = 7, Minimum = 2, Maximum = 10000, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid }); + model.Axes.Add(new LogarithmicAxis { Title = "Base 5.5", Position = AxisPosition.Top, Base = 5.5, Minimum = 1, Maximum = 100 }); + model.Axes.Add(new LogarithmicAxis { Title = "Base 2", Position = AxisPosition.Right, Base = 2, Minimum = 1, Maximum = 1000000 }); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/PolarPlotExamples.cs b/Source/Examples/ExampleLibrary/Axes/PolarPlotExamples.cs new file mode 100644 index 0000000..fde5807 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/PolarPlotExamples.cs @@ -0,0 +1,338 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Shows how to orient 0 degrees at the bottom and add E/W to indicate directions. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("Polar Plots"), Tags("Axes")] + public static class PolarPlotExamples + { + [Example("Spiral")] + public static PlotModel ArchimedeanSpiral() + { + var model = new PlotModel + { + Title = "Polar plot", + Subtitle = "Archimedean spiral with equation r(θ) = θ for 0 < θ < 6π", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + model.Axes.Add( + new AngleAxis + { + MajorStep = Math.PI / 4, + MinorStep = Math.PI / 16, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + FormatAsFractions = true, + FractionUnit = Math.PI, + FractionUnitSymbol = "π", + Minimum = 0, + Maximum = 2 * Math.PI + }); + model.Axes.Add(new MagnitudeAxis + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + }); + model.Series.Add(new FunctionSeries(t => t, t => t, 0, Math.PI * 6, 0.01)); + return model; + } + + [Example("Spiral2")] + public static PlotModel ArchimedeanSpiral2() + { + var model = ArchimedeanSpiral(); + model.Title += "(reversed angle axis)"; + var angleAxis = (AngleAxis)model.Axes[0]; + angleAxis.StartAngle = 360; + angleAxis.EndAngle = 0; + return model; + } + + [Example("Spiral with magnitude axis min and max")] + public static PlotModel ArchimedeanSpiral3() + { + var model = ArchimedeanSpiral(); + model.Title += " (axis Minimum = 10 and Maximum = 20)"; + var magnitudeAxis = (MagnitudeAxis)model.Axes[1]; + magnitudeAxis.Minimum = 10; + magnitudeAxis.Maximum = 20; + return model; + } + + [Example("Angle axis with offset angle")] + public static PlotModel OffsetAngles() + { + var model = new PlotModel + { + Title = "Offset angle axis", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + + var angleAxis = new AngleAxis + { + Minimum = 0, + Maximum = Math.PI * 2, + MajorStep = Math.PI / 4, + MinorStep = Math.PI / 16, + StringFormat = "0.00", + StartAngle = 30, + EndAngle = 390 + }; + model.Axes.Add(angleAxis); + model.Axes.Add(new MagnitudeAxis()); + model.Series.Add(new FunctionSeries(t => t, t => t, 0, Math.PI * 6, 0.01)); + + // Subscribe to the mouse down event on the line series. + model.MouseDown += (s, e) => + { + var increment = 0d; + + // Increment and decrement must be in degrees (corresponds to the StartAngle and EndAngle properties). + if (e.ChangedButton == OxyMouseButton.Left) + { + increment = 15; + } + + if (e.ChangedButton == OxyMouseButton.Right) + { + increment = -15; + } + + if (Math.Abs(increment) > double.Epsilon) + { + angleAxis.StartAngle += increment; + angleAxis.EndAngle += increment; + model.InvalidatePlot(false); + e.Handled = true; + } + }; + + return model; + } + + [Example("Semi-circle")] + public static PlotModel SemiCircle() + { + var model = new PlotModel + { + Title = "Semi-circle polar plot", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + model.Axes.Add( + new AngleAxis + { + Minimum = 0, + Maximum = 180, + MajorStep = 45, + MinorStep = 9, + StartAngle = 0, + EndAngle = 180, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Axes.Add(new MagnitudeAxis + { + Minimum = 0, + Maximum = 1, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x / 180 * Math.PI), t => t, 0, 180, 0.01)); + return model; + } + + [Example("Semi-circle offset angle axis range")] + public static PlotModel SemiCircleOffsetAngleAxisRange() + { + var model = new PlotModel + { + Title = "Semi-circle polar plot", + Subtitle = "Angle axis range offset to -180 - 180", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + model.Axes.Add( + new AngleAxis + { + Minimum = -180, + Maximum = 180, + MajorStep = 45, + MinorStep = 9, + StartAngle = 0, + EndAngle = 360, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Axes.Add(new MagnitudeAxis + { + Minimum = 0, + Maximum = 1, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x / 180 * Math.PI), t => t, 0, 180, 0.01)); + return model; + } + + /// + /// Shows how to orient 0 degrees at the bottom and add E/W to indicate directions. + /// + /// + [Example("East/west directions")] + public static PlotModel EastWestDirections() + { + var model = new PlotModel + { + Title = "East/west directions", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0), + }; + model.Axes.Add( + new AngleAxis + { + Minimum = 0, + Maximum = 360, + MajorStep = 30, + MinorStep = 30, + StartAngle = -90, + EndAngle = 270, + LabelFormatter = angle => + { + if (angle > 0 && angle < 180) + { + return angle + "E"; + } + + if (angle > 180) + { + return (360 - angle) + "W"; + } + + return angle.ToString(); + }, + MajorGridlineStyle = LineStyle.Dot, + MinorGridlineStyle = LineStyle.None + }); + model.Axes.Add(new MagnitudeAxis + { + Minimum = 0, + Maximum = 1, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x / 180 * Math.PI), t => t, 0, 180, 0.01)); + return model; + } + + [Example("Semi-circle full plot area")] + public static PlotModel SemiCircleFullPlotArea() + { + var model = new PlotModel + { + Title = "Semi-circle polar plot filling the plot area", + Subtitle = "The center can be move using the right mouse button", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(1), + }; + model.Axes.Add( + new AngleAxisFullPlotArea + { + Minimum = 0, + Maximum = 180, + MajorStep = 45, + MinorStep = 9, + StartAngle = 0, + EndAngle = 180, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Axes.Add(new MagnitudeAxisFullPlotArea + { + Minimum = 0, + Maximum = 1, + MidshiftH = 0, + MidshiftV = 0.9d, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x / 180 * Math.PI), t => t, 0, 180, 0.01)); + return model; + } + + [Example("Spiral full plot area")] + public static PlotModel ArchimedeanSpiralFullPlotArea() + { + var model = CreateFullPlotAreaPlotModel(); + model.Series.Add(new FunctionSeries(t => t, t => t, 0, Math.PI * 6, 0.01)); + return model; + } + + [Example("Spiral full plot area with negative minimum")] + public static PlotModel SpiralWithNegativeMinium() + { + var model = CreateFullPlotAreaPlotModel(); + model.Title += " with a negative minimum"; + model.Series.Add(new FunctionSeries(t => t, t => t, -Math.PI * 6, Math.PI * 6, 0.01)); + return model; + } + + [Example("Spiral full plot area with positive minimum")] + public static PlotModel SpiralWithPositiveMinium() + { + var model = CreateFullPlotAreaPlotModel(); + model.Title += " with a positive minimum"; + model.Series.Add(new FunctionSeries(t => t, t => t, Math.PI * 6, Math.PI * 12, 0.01)); + return model; + } + + private static PlotModel CreateFullPlotAreaPlotModel() + { + var model = new PlotModel + { + Title = "Polar plot filling the plot area", + Subtitle = "The center can be move using the right mouse button", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(1), + }; + + model.Axes.Add( + new AngleAxisFullPlotArea + { + MajorStep = Math.PI / 4, + MinorStep = Math.PI / 16, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + FormatAsFractions = true, + FractionUnit = Math.PI, + FractionUnitSymbol = "π", + Minimum = 0, + Maximum = 2 * Math.PI + }); + + model.Axes.Add(new MagnitudeAxisFullPlotArea + { + MidshiftH = -0.1d, + MidshiftV = -0.25d, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid + }); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/RangeColorAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/RangeColorAxisExamples.cs new file mode 100644 index 0000000..6ccb5b2 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/RangeColorAxisExamples.cs @@ -0,0 +1,84 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("RangeColorAxis"), Tags("Axes")] + public class RangeColorAxisExamples + { + [Example("ScatterSeries with Reversed RangeColorAxis (Horizontal)")] + public static PlotModel ReversedHorizontalRangeColorAxis() + { + return RangeColorAxis(AxisPosition.Top, true); + } + + [Example("ScatterSeries with Reversed RangeColorAxis (Vertical)")] + public static PlotModel ReversedVerticalRangeColorAxis() + { + return RangeColorAxis(AxisPosition.Right, true); + } + + [Example("ScatterSeries with RangeColorAxis (Horizontal)")] + public static PlotModel HorizontalRangeColorAxis() + { + return RangeColorAxis(AxisPosition.Top, false); + } + + [Example("ScatterSeries with RangeColorAxis (Vertical)")] + public static PlotModel VerticalRangeColorAxis() + { + return RangeColorAxis(AxisPosition.Right, false); + } + + private static PlotModel RangeColorAxis(AxisPosition position, bool reverseAxis) + { + int n = 1000; + + string modelTitle = reverseAxis + ? string.Format("ScatterSeries and Reversed RangeColorAxis (n={0})", n) + : string.Format("ScatterSeries and RangeColorAxis (n={0})", n); + + var model = new PlotModel + { + Title = modelTitle, + Background = OxyColors.LightGray + }; + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var rca = new RangeColorAxis { Position = position, Maximum = 2, Minimum = -2 }; + rca.AddRange(0, 0.5, OxyColors.Blue); + rca.AddRange(-0.2, -0.1, OxyColors.Red); + + if (reverseAxis) + { + rca.StartPosition = 1; + rca.EndPosition = 0; + } + + model.Axes.Add(rca); + + var s1 = new ScatterSeries { MarkerType = MarkerType.Square, MarkerSize = 6, }; + + var random = new Random(13); + for (int i = 0; i < n; i++) + { + double x = (random.NextDouble() * 2.2) - 1.1; + s1.Points.Add(new ScatterPoint(x, random.NextDouble()) { Value = x }); + } + + model.Series.Add(s1); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Axes/TimeSpanAxisExamples.cs b/Source/Examples/ExampleLibrary/Axes/TimeSpanAxisExamples.cs new file mode 100644 index 0000000..3111ca7 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Axes/TimeSpanAxisExamples.cs @@ -0,0 +1,74 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.ObjectModel; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("TimeSpanAxis"), Tags("Axes")] + public static class TimeSpanAxisExamples + { + public class TimeValue + { + public TimeSpan Time { get; set; } + public double Value { get; set; } + } + + [Example("Default StringFormat")] + public static PlotModel TimeSpanaxisPlotModelDefault() + { + return TimeSpanaxisPlotModel(null); + } + + [Example("StringFormat = 'h:mm'")] + public static PlotModel TimeSpanaxisPlotModel1() + { + return TimeSpanaxisPlotModel("h:mm"); + } + + private static PlotModel TimeSpanaxisPlotModel(string stringFormat) + { + var start = new TimeSpan(0, 0, 0, 0); + var end = new TimeSpan(0, 24, 0, 0); + double increment = 3600; + + // Create a random data collection + var r = new Random(7); + var data = new Collection(); + var current = start; + while (current <= end) + { + data.Add(new TimeValue { Time = current, Value = r.NextDouble() }); + current = current.Add(new TimeSpan(0, 0, (int)increment)); + } + + var plotModel1 = new PlotModel { Title = "TimeSpan axis" }; + var timeSpanAxis1 = new TimeSpanAxis { Position = AxisPosition.Bottom, StringFormat = stringFormat }; + plotModel1.Axes.Add(timeSpanAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Left }; + plotModel1.Axes.Add(linearAxis1); + var lineSeries1 = new LineSeries + { + Color = OxyColor.FromArgb(255, 78, 154, 6), + MarkerFill = OxyColor.FromArgb(255, 78, 154, 6), + MarkerStroke = OxyColors.ForestGreen, + MarkerType = MarkerType.Plus, + StrokeThickness = 1, + DataFieldX = "Time", + DataFieldY = "Value", + ItemsSource = data + }; + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/CustomSeries/CustomSeriesExamples.cs b/Source/Examples/ExampleLibrary/CustomSeries/CustomSeriesExamples.cs new file mode 100644 index 0000000..659ab72 --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/CustomSeriesExamples.cs @@ -0,0 +1,323 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("Custom series"), Tags("Series")] + public static class CustomSeriesExamples + { + [Example("ErrorSeries")] + public static PlotModel ErrorSeries() + { + int n = 20; + + var model = new PlotModel { Title = "ErrorSeries" }; + var l = new Legend + { + LegendPosition = LegendPosition.BottomRight + }; + + model.Legends.Add(l); + + var s1 = new ErrorSeries { Title = "Measurements" }; + var random = new Random(31); + double x = 0; + double y = 0; + for (int i = 0; i < n; i++) + { + x += 2 + (random.NextDouble() * 10); + y += 1 + random.NextDouble(); + double xe = 1 + (random.NextDouble() * 2); + double ye = 1 + (random.NextDouble() * 2); + s1.Points.Add(new ErrorItem(x, y, xe, ye)); + } + + model.Series.Add(s1); + return model; + } + + [Example("LineSegmentSeries")] + public static PlotModel LineSegmentSeries() + { + var model = new PlotModel { Title = "LineSegmentSeries" }; + + var lss1 = new LineSegmentSeries { Title = "The first series" }; + + // First segment + lss1.Points.Add(new DataPoint(0, 3)); + lss1.Points.Add(new DataPoint(2, 3.2)); + + // Second segment + lss1.Points.Add(new DataPoint(2, 2.7)); + lss1.Points.Add(new DataPoint(7, 2.9)); + + model.Series.Add(lss1); + + var lss2 = new LineSegmentSeries { Title = "The second series" }; + + // First segment + lss2.Points.Add(new DataPoint(1, -3)); + lss2.Points.Add(new DataPoint(2, 10)); + + // Second segment + lss2.Points.Add(new DataPoint(0, 4.8)); + lss2.Points.Add(new DataPoint(7, 2.3)); + + // A very short segment + lss2.Points.Add(new DataPoint(6, 4)); + lss2.Points.Add(new DataPoint(6, 4 + 1e-8)); + + model.Series.Add(lss2); + + return model; + } + + [Example("FlagSeries")] + public static PlotModel FlagSeries() + { + var model = new PlotModel { Title = "FlagSeries" }; + + var s1 = new FlagSeries { Title = "Incidents", Color = OxyColors.Red }; + s1.Values.Add(2); + s1.Values.Add(3); + s1.Values.Add(5); + s1.Values.Add(7); + s1.Values.Add(11); + s1.Values.Add(13); + s1.Values.Add(17); + s1.Values.Add(19); + + model.Series.Add(s1); + return model; + } + + [Example("MatrixSeries - diagonal matrix")] + public static PlotModel DiagonalMatrix() + { + var model = new PlotModel(); + + var matrix = new double[3, 3]; + matrix[0, 0] = 1; + matrix[1, 1] = 2; + matrix[2, 2] = 3; + + // Reverse the vertical axis + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Series.Add(new MatrixSeries { Matrix = matrix, ShowDiagonal = true }); + + return model; + } + + [Example("PolarHeatMap")] + public static PlotModel PolarHeatMap() + { + var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) }; + + var matrix = new double[2, 2]; + matrix[0, 0] = 0; + matrix[0, 1] = 2; + matrix[1, 0] = 1.5; + matrix[1, 1] = 0.2; + + model.Axes.Add(new AngleAxis { StartAngle = 0, EndAngle = 360, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 }); + model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false }); + + return model; + } + + [Example("PolarHeatMap Reversed Angle Axis")] + public static PlotModel PolarHeatMapReversedAngleAxis() + { + var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) }; + + var matrix = new double[2, 2]; + matrix[0, 0] = 0; + matrix[0, 1] = 2; + matrix[1, 0] = 1.5; + matrix[1, 1] = 0.2; + + model.Axes.Add(new AngleAxis { StartAngle = 360, EndAngle = 0, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 }); + model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false }); + + return model; + } + + [Example("PolarHeatMap Rotated CounterClockwise 90")] + public static PlotModel PolarHeatMapRotatedCounterClockwise90() + { + var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) }; + + var matrix = new double[2, 2]; + matrix[0, 0] = 0; + matrix[0, 1] = 2; + matrix[1, 0] = 1.5; + matrix[1, 1] = 0.2; + + model.Axes.Add(new AngleAxis { StartAngle = 90, EndAngle = 90+360, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 }); + model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false }); + + return model; + } + + [Example("PolarHeatMap Rotated CounterClockwise on PI degrees")] + public static PlotModel PolarHeatMapRotatedCounterClockwisePi() + { + var model = new PlotModel { Title = "Polar heat map", PlotMargins = new OxyThickness(40, 80, 40, 40), PlotType = PlotType.Polar, PlotAreaBorderThickness = new OxyThickness(0) }; + + var matrix = new double[2, 2]; + matrix[0, 0] = 0; + matrix[0, 1] = 2; + matrix[1, 0] = 1.5; + matrix[1, 1] = 0.2; + + model.Axes.Add(new AngleAxis { StartAngle = Math.PI, EndAngle = Math.PI + 360, Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 15 }); + model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 100, MajorStep = 25, MinorStep = 5 }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = false }); + + return model; + } + + [Example("PolarHeatMap (interpolated)")] + public static PlotModel PolarHeatMapInterpolated() + { + var model = PolarHeatMap(); + model.Title = "Polar heat map (interpolated)"; + ((PolarHeatMapSeries)model.Series[0]).Interpolate = true; + return model; + } + + [Example("PolarHeatMap fixed size image")] + public static PlotModel PolarHeatMapFixed() + { + var model = PolarHeatMap(); + model.Title = "Polar heat map with fixed size image"; + ((PolarHeatMapSeries)model.Series[0]).ImageSize = 800; + return model; + } + + [Example("PolarHeatMap on linear axes")] + public static PlotModel PolarHeatMapLinearAxes() + { + var model = new PlotModel { Title = "Polar heat map on linear axes" }; + + var matrix = new double[2, 2]; + matrix[0, 0] = 0; + matrix[0, 1] = 2; + matrix[1, 0] = 1.5; + matrix[1, 1] = 0.2; + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -100, Maximum = 100 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100 }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Rainbow(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + model.Series.Add(new PolarHeatMapSeries { Data = matrix, Angle0 = 30, Angle1 = 150, Magnitude0 = 0, Magnitude1 = 80, Interpolate = true }); + + return model; + } + + [Example("PolarHeatMap linear axes, fixed size image (256x256)")] + public static PlotModel PolarHeatMapLinearAxesFixed256() + { + var model = PolarHeatMapLinearAxes(); + model.Title = "Polar heat map on linear axes & fixed size image (256x256)"; + ((PolarHeatMapSeries)model.Series[0]).ImageSize = 256; + return model; + } + + [Example("PolarHeatMap linear axes, fixed size image (1000x1000)")] + public static PlotModel PolarHeatMapLinearAxesFixed1000() + { + var model = PolarHeatMapLinearAxes(); + model.Title = "Polar heat map on linear axes & fixed size image (1000x1000)"; + ((PolarHeatMapSeries)model.Series[0]).ImageSize = 1000; + return model; + } + + [Example("Design structure matrix (DSM)")] + public static PlotModel DesignStructureMatrix() + { + // See also http://en.wikipedia.org/wiki/Design_structure_matrix + var data = new double[7, 7]; + + // indexing: data[column,row] + data[1, 0] = 1; + data[5, 0] = 1; + data[3, 1] = 1; + data[0, 2] = 1; + data[6, 2] = 1; + data[4, 3] = 1; + data[1, 4] = 1; + data[5, 4] = 1; + data[2, 5] = 1; + data[0, 6] = 1; + data[4, 6] = 1; + + for (int i = 0; i < 7; i++) + { + data[i, i] = -1; + } + + var model = new PlotModel { Title = "Design structure matrix (DSM)" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.None, Palette = new OxyPalette(OxyColors.White, OxyColors.LightGreen), LowColor = OxyColors.Black, Minimum = 0, IsAxisVisible = false }); + var topAxis = new CategoryAxis + { + Position = AxisPosition.Top + }; + topAxis.Labels.AddRange(new[] { "A", "B", "C", "D", "E", "F", "G" }); + model.Axes.Add(topAxis); + var leftAxis = new CategoryAxis + { + Position = AxisPosition.Left, + StartPosition = 1, + EndPosition = 0 + }; + leftAxis.Labels.AddRange(new[] { "Element A", "Element B", "Element C", "Element D", "Element E", "Element F", "Element G" }); + model.Axes.Add(leftAxis); + + var hms = new DesignStructureMatrixSeries + { + Data = data, + Interpolate = false, + LabelFormatString = "#", + LabelFontSize = 0.25, + X0 = 0, + X1 = data.GetLength(0) - 1, + Y0 = 0, + Y1 = data.GetLength(1) - 1, + }; + + model.Series.Add(hms); + return model; + } + } + + public class DesignStructureMatrixSeries : HeatMapSeries + { + protected override string GetLabel(double v, int i, int j) + { + if (i == j) + { + return ((CategoryAxis)this.XAxis).Labels[i]; + } + + return base.GetLabel(v, i, j); + } + } +} diff --git a/Source/Examples/ExampleLibrary/CustomSeries/ErrorItem.cs b/Source/Examples/ExampleLibrary/CustomSeries/ErrorItem.cs new file mode 100644 index 0000000..2997190 --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/ErrorItem.cs @@ -0,0 +1,70 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an error item. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + + /// + /// Represents an error item. + /// + public class ErrorItem + { + /// + /// Initializes a new instance of the class. + /// + public ErrorItem() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The x. + /// The y. + /// The xerror. + /// The yerror. + public ErrorItem(double x, double y, double xerror, double yerror) + { + this.X = x; + this.Y = y; + this.XError = xerror; + this.YError = yerror; + } + + /// + /// Gets or sets the X. + /// + public double X { get; set; } + + /// + /// Gets or sets the Y. + /// + public double Y { get; set; } + + /// + /// Gets or sets the X error. + /// + public double XError { get; set; } + + /// + /// Gets or sets the Y error. + /// + public double YError { get; set; } + + /// + /// Returns c# code that generates this instance. + /// + /// C# code. + public string ToCode() + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1},{2},{3}", this.X, this.Y, this.XError, this.YError); + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/CustomSeries/ErrorSeries.cs b/Source/Examples/ExampleLibrary/CustomSeries/ErrorSeries.cs new file mode 100644 index 0000000..bac575a --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/ErrorSeries.cs @@ -0,0 +1,163 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents an error series. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Series; + + /// + /// Represents an error series. + /// + public class ErrorSeries : XYAxisSeries + { + /// + /// The list of error items. + /// + private readonly List points = new List(); + + /// + /// Initializes a new instance of the class. + /// + public ErrorSeries() + { + this.Color = OxyColors.Black; + this.StrokeThickness = 1; + } + + /// + /// Gets or sets the color. + /// + /// The color. + public OxyColor Color { get; set; } + + /// + /// Gets the list of points. + /// + /// A list of . + public List Points + { + get + { + return this.points; + } + } + + /// + /// Gets or sets the stroke thickness. + /// + /// The stroke thickness. + public double StrokeThickness { get; set; } + + /// + /// Renders the series on the specified render context. + /// + /// The rendering context. + public override void Render(IRenderContext rc) + { + var points = this.Points; + if (points.Count == 0) + { + return; + } + + this.VerifyAxes(); + + int n = points.Count; + + // Transform all points to screen coordinates + var segments = new List(n * 6); + for (int i = 0; i < n; i++) + { + var sp = XAxis.Transform(points[i].X, points[i].Y, YAxis); + var ei = points[i]; + double errorx = ei != null ? ei.XError * XAxis.Scale : 0; + double errory = ei != null ? ei.YError * Math.Abs(YAxis.Scale) : 0; + double d = 4; + + if (errorx > 0) + { + var p0 = new ScreenPoint(sp.X - (errorx * 0.5), sp.Y); + var p1 = new ScreenPoint(sp.X + (errorx * 0.5), sp.Y); + segments.Add(p0); + segments.Add(p1); + segments.Add(new ScreenPoint(p0.X, p0.Y - d)); + segments.Add(new ScreenPoint(p0.X, p0.Y + d)); + segments.Add(new ScreenPoint(p1.X, p1.Y - d)); + segments.Add(new ScreenPoint(p1.X, p1.Y + d)); + } + + if (errory > 0) + { + var p0 = new ScreenPoint(sp.X, sp.Y - (errory * 0.5)); + var p1 = new ScreenPoint(sp.X, sp.Y + (errory * 0.5)); + segments.Add(p0); + segments.Add(p1); + segments.Add(new ScreenPoint(p0.X - d, p0.Y)); + segments.Add(new ScreenPoint(p0.X + d, p0.Y)); + segments.Add(new ScreenPoint(p1.X - d, p1.Y)); + segments.Add(new ScreenPoint(p1.X + d, p1.Y)); + } + } + + // clip the line segments with the clipping rectangle + for (int i = 0; i + 1 < segments.Count; i += 2) + { + rc.DrawReducedLine( + new[] { segments[i], segments[i + 1] }, + 0, + this.GetSelectableColor(this.Color), + this.StrokeThickness, + this.EdgeRenderingMode, + null, + LineJoin.Bevel); + } + } + + /// + /// Renders the legend symbol on the specified rendering context. + /// + /// The rendering context. + /// The legend rectangle. + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + double xmid = (legendBox.Left + legendBox.Right) * 0.5; + double ymid = (legendBox.Top + legendBox.Bottom) * 0.5; + var pts = new[] + { + new ScreenPoint(legendBox.Left, ymid), + new ScreenPoint(legendBox.Right, ymid), + new ScreenPoint(legendBox.Left, ymid - 2), + new ScreenPoint(legendBox.Left, ymid + 3), + new ScreenPoint(legendBox.Right, ymid - 2), + new ScreenPoint(legendBox.Right, ymid + 3), + + new ScreenPoint(xmid, legendBox.Top), + new ScreenPoint(xmid, legendBox.Bottom), + new ScreenPoint(xmid - 2, legendBox.Top), + new ScreenPoint(xmid + 3, legendBox.Top), + new ScreenPoint(xmid - 2, legendBox.Bottom), + new ScreenPoint(xmid + 3, legendBox.Bottom) + }; + rc.DrawLineSegments(pts, this.GetSelectableColor(this.Color), this.StrokeThickness, this.EdgeRenderingMode, null, LineJoin.Miter); + } + + /// + /// Updates the maximum and minimum values of the series. + /// + protected override void UpdateMaxMin() + { + base.UpdateMaxMin(); + this.InternalUpdateMaxMin(this.points, p => p.X - p.XError, p => p.X + p.XError, p => p.Y - p.YError, p => p.Y + p.YError); + } + } +} diff --git a/Source/Examples/ExampleLibrary/CustomSeries/FlagSeries.cs b/Source/Examples/ExampleLibrary/CustomSeries/FlagSeries.cs new file mode 100644 index 0000000..2dbc036 --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/FlagSeries.cs @@ -0,0 +1,236 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Renders a 'flag' above the x-axis at the specified positions (in the Values list). +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System.Collections.Generic; + using System.Linq; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Renders a 'flag' above the x-axis at the specified positions (in the Values list). + /// + public class FlagSeries : ItemsSeries + { + /// + /// The symbol position (y coordinate). + /// + private double symbolPosition; + + /// + /// The symbol text size. + /// + private OxySize symbolSize; + + /// + /// Initializes a new instance of the class. + /// + public FlagSeries() + { + this.Values = new List(); + this.Color = OxyColors.Black; + this.FontSize = 10; + this.Symbol = ((char)0xEA).ToString(); + this.Font = "Wingdings 2"; + this.TrackerFormatString = "{0}: {1}"; + } + + /// + /// Gets or sets the color of the symbols. + /// + /// The color. + public OxyColor Color { get; set; } + + /// + /// Gets the maximum value. + /// + /// The maximum value. + public double MaximumX { get; private set; } + + /// + /// Gets the minimum value. + /// + /// The minimum value. + public double MinimumX { get; private set; } + + /// + /// Gets or sets the symbol to draw at each value. + /// + /// The symbol. + public string Symbol { get; set; } + + /// + /// Gets the values. + /// + /// The values. + public List Values { get; private set; } + + /// + /// Gets the x-axis. + /// + /// The x-axis. + public Axis XAxis { get; private set; } + + /// + /// Gets or sets the x-axis key. + /// + /// The x-axis key. + public string XAxisKey { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// A TrackerHitResult for the current hit. + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + foreach (var v in this.Values) + { + if (double.IsNaN(v) || v < this.XAxis.ActualMinimum || v > this.XAxis.ActualMaximum) + { + continue; + } + + double x = this.XAxis.Transform(v); + var r = new OxyRect(x - (this.symbolSize.Width / 2), this.symbolPosition - this.symbolSize.Height, this.symbolSize.Width, this.symbolSize.Height); + if (r.Contains(point)) + { + return new TrackerHitResult + { + Series = this, + DataPoint = new DataPoint(v, double.NaN), + Position = new ScreenPoint(x, this.symbolPosition - this.symbolSize.Height), + Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, this.Title, v) + }; + } + } + + return null; + } + + /// + /// Renders the series on the specified render context. + /// + /// The rendering context. + public override void Render(IRenderContext rc) + { + if (this.XAxis == null) + { + return; + } + + this.symbolPosition = this.PlotModel.PlotArea.Bottom; + this.symbolSize = rc.MeasureText(this.Symbol, this.ActualFont, this.ActualFontSize); + foreach (var v in this.Values) + { + if (double.IsNaN(v) || v < this.XAxis.ClipMinimum || v > this.XAxis.ClipMaximum) + { + continue; + } + + double x = this.XAxis.Transform(v); + rc.DrawText( + new ScreenPoint(x, this.symbolPosition), + this.Symbol, + this.Color, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Bottom); + } + } + + /// + /// Renders the legend symbol on the specified render context. + /// + /// The rendering context. + /// The legend rectangle. + public override void RenderLegend(IRenderContext rc, OxyRect legendBox) + { + rc.DrawText( + legendBox.Center, + this.Symbol, + this.Color, + this.ActualFont, + this.ActualFontSize, + this.ActualFontWeight, + 0, + HorizontalAlignment.Center, + VerticalAlignment.Middle); + } + + /// + /// Check if this data series requires X/Y axes. (e.g. Pie series do not require axes) + /// + /// True if no axes are required. + protected override bool AreAxesRequired() + { + return true; + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected override void EnsureAxes() + { + this.XAxis = this.XAxisKey != null ? + this.PlotModel.GetAxis(this.XAxisKey) : + this.PlotModel.DefaultXAxis; + } + + /// + /// Check if the data series is using the specified axis. + /// + /// An axis which should be checked if used + /// True if the axis is in use. + protected override bool IsUsing(Axis axis) + { + return axis == this.XAxis; + } + + /// + /// Sets default values (colors, line style etc) from the plot model. + /// + protected override void SetDefaultValues() + { + } + + /// + /// Updates the axis maximum and minimum values. + /// + protected override void UpdateAxisMaxMin() + { + this.XAxis.Include(this.MinimumX); + this.XAxis.Include(this.MaximumX); + } + + /// + /// Updates the data from the ItemsSource. + /// + protected override void UpdateData() + { + // todo + } + + /// + /// Updates the maximum and minimum values of the series. + /// + protected override void UpdateMaxMin() + { + this.MinimumX = this.Values.Min(); + this.MaximumX = this.Values.Max(); + } + } +} diff --git a/Source/Examples/ExampleLibrary/CustomSeries/LineSegmentSeries.cs b/Source/Examples/ExampleLibrary/CustomSeries/LineSegmentSeries.cs new file mode 100644 index 0000000..411b9d3 --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/LineSegmentSeries.cs @@ -0,0 +1,165 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a line series where the points collection define line segments. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + using OxyPlot; + using OxyPlot.Series; + + /// + /// Represents a line series where the points collection define line segments. + /// + public class LineSegmentSeries : LineSeries + { + /// + /// Initializes a new instance of the class. + /// + public LineSegmentSeries() + { + this.ShowVerticals = true; + this.Epsilon = 1e-8; + } + + /// + /// Gets or sets a value indicating whether to show vertical lines where there is no gap in x-coordinate. + /// + /// true if verticals should be shown; otherwise, false. + public bool ShowVerticals { get; set; } + + /// + /// Gets or sets the x-coordinate gap tolerance. + /// + /// The epsilon value. + public double Epsilon { get; set; } + + /// + /// Renders the series on the specified rendering context. + /// + /// The rendering context. + public override void Render(IRenderContext rc) + { + if (Points.Count == 0) + { + return; + } + + if (Points.Count % 2 != 0) + { + throw new InvalidOperationException("The number of points should be even."); + } + + if (this.XAxis == null || this.YAxis == null) + { + throw new InvalidOperationException("Axis has not been defined."); + } + + var screenPoints = Points.Select(this.Transform).ToList(); + var verticalLines = new List(); + + for (int i = 0; i < screenPoints.Count; i += 2) + { + if (screenPoints[i].DistanceToSquared(screenPoints[i + 1]) < this.StrokeThickness) + { + screenPoints[i] = new ScreenPoint(screenPoints[i].X - (this.StrokeThickness * 0.5), screenPoints[i].Y); + screenPoints[i + 1] = new ScreenPoint(screenPoints[i].X + (this.StrokeThickness * 0.5), screenPoints[i].Y); + } + + if (this.ShowVerticals && i > 0 && Math.Abs(screenPoints[i - 1].X - screenPoints[i].X) < this.Epsilon) + { + verticalLines.Add(screenPoints[i - 1]); + verticalLines.Add(screenPoints[i]); + } + } + + if (this.StrokeThickness > 0) + { + if (this.LineStyle != LineStyle.None) + { + rc.DrawLineSegments(screenPoints, this.ActualColor, this.StrokeThickness, this.EdgeRenderingMode, this.LineStyle.GetDashArray(), this.LineJoin); + } + + rc.DrawLineSegments(verticalLines, this.ActualColor, this.StrokeThickness / 3, this.EdgeRenderingMode, LineStyle.Dash.GetDashArray(), this.LineJoin); + } + + rc.DrawMarkers(screenPoints, this.MarkerType, null, this.MarkerSize, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, this.EdgeRenderingMode); + } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// A TrackerHitResult for the current hit. + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + var points = this.Points; + + if (points == null) + { + return null; + } + + var spn = default(ScreenPoint); + var dpn = default(DataPoint); + double index = -1; + + double minimumDistance = double.MaxValue; + + for (int i = 0; i + 1 < points.Count; i += 2) + { + var p1 = points[i]; + var p2 = points[i + 1]; + if (!this.IsValidPoint(p1) || !this.IsValidPoint(p2)) + { + continue; + } + + var sp1 = this.Transform(p1); + var sp2 = this.Transform(p2); + + // Find the nearest point on the line segment. + var spl = ScreenPointHelper.FindPointOnLine(point, sp1, sp2); + + if (ScreenPoint.IsUndefined(spl)) + { + // P1 && P2 coincident + continue; + } + + double l2 = (point - spl).LengthSquared; + + if (l2 < minimumDistance) + { + double u = (spl - sp1).Length / (sp2 - sp1).Length; + dpn = new DataPoint(p1.X + (u * (p2.X - p1.X)), p1.Y + (u * (p2.Y - p1.Y))); + spn = spl; + minimumDistance = l2; + index = i + u; + } + } + + if (minimumDistance < double.MaxValue) + { + return new TrackerHitResult + { + Series = this, + DataPoint = dpn, + Position = spn, + Item = this.GetItem((int)index), + Index = index + }; + } + + return null; + } + } +} diff --git a/Source/Examples/ExampleLibrary/CustomSeries/MatrixSeries.cs b/Source/Examples/ExampleLibrary/CustomSeries/MatrixSeries.cs new file mode 100644 index 0000000..3462d78 --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/MatrixSeries.cs @@ -0,0 +1,236 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides a series that visualizes the structure of a matrix. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Series; + + /// + /// Provides a series that visualizes the structure of a matrix. + /// + public class MatrixSeries : XYAxisSeries + { + /// + /// The image + /// + private OxyImage image; + + /// + /// The matrix + /// + private double[,] matrix; + + /// + /// Initializes a new instance of the class. + /// + public MatrixSeries() + { + this.GridInterval = 1; + this.ShowDiagonal = false; + this.MinimumGridLineDistance = 4; + this.GridColor = OxyColors.LightGray; + this.BorderColor = OxyColors.Gray; + this.NotZeroColor = OxyColors.Black; + this.ZeroTolerance = 0; + this.TrackerFormatString = "{0}\r\n[{1},{2}] = {3}"; + } + + /// + /// Gets or sets the matrix. + /// + public double[,] Matrix + { + get + { + return this.matrix; + } + + set + { + this.image = null; + this.matrix = value; + } + } + + /// + /// Gets or sets the interval between the grid lines (the grid is hidden if value is 0). + /// + public int GridInterval { get; set; } + + /// + /// Gets or sets a value indicating whether to show the diagonal. + /// + /// true if the diagonal should be shown; otherwise, false. + public bool ShowDiagonal { get; set; } + + /// + /// Gets or sets the minimum grid line distance. + /// + public double MinimumGridLineDistance { get; set; } + + /// + /// Gets or sets the color of the grid. + /// + /// The color of the grid. + public OxyColor GridColor { get; set; } + + /// + /// Gets or sets the color of the border around the matrix. + /// + /// The color of the border. + public OxyColor BorderColor { get; set; } + + /// + /// Gets or sets the color of the not zero elements of the matrix. + /// + public OxyColor NotZeroColor { get; set; } + + /// + /// Gets or sets the zero tolerance (inclusive). + /// + /// The zero tolerance. + public double ZeroTolerance { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// A TrackerHitResult for the current hit. + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + var dp = this.InverseTransform(point); + int i = (int)dp.Y; + int j = (int)dp.X; + + if (i >= 0 && i < this.matrix.GetLength(0) && j >= 0 && j < this.matrix.GetLength(1)) + { + var value = this.matrix[i, j]; + return new TrackerHitResult + { + Series = this, + DataPoint = dp, + Position = point, + Item = null, + Index = -1, + Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, this.Title, i, j, value) + }; + } + + return null; + } + + /// + /// Renders the series on the specified render context. + /// + /// The rendering context. + public override void Render(IRenderContext rc) + { + if (this.Matrix == null) + { + return; + } + + int m = this.Matrix.GetLength(0); + int n = this.Matrix.GetLength(1); + var p0 = this.Transform(0, 0); + var p1 = this.Transform(n, m); + + // note matrix index [i,j] maps to image index [j,i] + if (this.image == null) + { + var pixels = new OxyColor[n, m]; + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + pixels[j, i] = Math.Abs(this.Matrix[i, j]) <= this.ZeroTolerance ? OxyColors.Transparent : this.NotZeroColor; + } + } + + this.image = OxyImage.Create(pixels, ImageFormat.Png); + } + + var x0 = Math.Min(p0.X, p1.X); + var y0 = Math.Min(p0.Y, p1.Y); + var w = Math.Abs(p0.X - p1.X); + var h = Math.Abs(p0.Y - p1.Y); + rc.DrawImage(this.image, x0, y0, w, h, 1, false); + + var points = new List(); + if (this.GridInterval > 0) + { + var p2 = this.Transform(this.GridInterval, this.GridInterval); + if (Math.Abs(p2.Y - p0.Y) > this.MinimumGridLineDistance) + { + for (int i = 1; i < n; i += this.GridInterval) + { + points.Add(this.Transform(0, i)); + points.Add(this.Transform(n, i)); + } + } + + if (Math.Abs(p2.X - p0.X) > this.MinimumGridLineDistance) + { + for (int j = 1; j < m; j += this.GridInterval) + { + points.Add(this.Transform(j, 0)); + points.Add(this.Transform(j, m)); + } + } + } + + if (this.ShowDiagonal) + { + points.Add(this.Transform(0, 0)); + points.Add(this.Transform(n, m)); + } + + rc.DrawLineSegments(points, this.GridColor, 1, this.EdgeRenderingMode, null, LineJoin.Miter); + + if (this.BorderColor.IsVisible()) + { + var borderPoints = new[] + { + this.Transform(0, 0), + this.Transform(m, 0), + this.Transform(0, n), + this.Transform(m, n), + this.Transform(0, 0), + this.Transform(0, n), + this.Transform(m, 0), + this.Transform(m, n) + }; + + rc.DrawLineSegments(borderPoints, this.BorderColor, 1, this.EdgeRenderingMode, null, LineJoin.Miter); + } + } + + /// + /// Updates the maximum and minimum values of the series. + /// + protected override void UpdateMaxMin() + { + base.UpdateMaxMin(); + if (this.Matrix == null) + { + return; + } + + this.MinX = 0; + this.MaxX = this.Matrix.GetLength(1); + this.MinY = 0; + this.MaxY = this.Matrix.GetLength(0); + } + } +} diff --git a/Source/Examples/ExampleLibrary/CustomSeries/PolarHeatMapSeries.cs b/Source/Examples/ExampleLibrary/CustomSeries/PolarHeatMapSeries.cs new file mode 100644 index 0000000..beddca1 --- /dev/null +++ b/Source/Examples/ExampleLibrary/CustomSeries/PolarHeatMapSeries.cs @@ -0,0 +1,397 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Implements a polar heat map series. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace OxyPlot.Series +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot.Axes; + + /// + /// Implements a polar heat map series. + /// + public class PolarHeatMapSeries : XYAxisSeries + { + /// + /// The image + /// + private OxyImage image; + + /// + /// The pixels + /// + private OxyColor[,] pixels; + + /// + /// Initializes a new instance of the class. + /// + public PolarHeatMapSeries() + { + this.Interpolate = true; + } + + /// + /// Gets or sets the size of the image - if set to 0, the image will be generated at every update. + /// + /// The size of the image. + public int ImageSize { get; set; } + + /// + /// Gets or sets the x-coordinate of the left column mid point. + /// + public double Angle0 { get; set; } + + /// + /// Gets or sets the x-coordinate of the right column mid point. + /// + public double Angle1 { get; set; } + + /// + /// Gets or sets the y-coordinate of the top row mid point. + /// + public double Magnitude0 { get; set; } + + /// + /// Gets or sets the y-coordinate of the bottom row mid point. + /// + public double Magnitude1 { get; set; } + + /// + /// Gets or sets the data array. + /// + /// Note that the indices of the data array refer to [x,y]. + public double[,] Data { get; set; } + + /// + /// Gets or sets a value indicating whether to interpolate when rendering. + /// + /// This property is not supported on all platforms. + public bool Interpolate { get; set; } + + /// + /// Gets or sets the minimum value of the dataset. + /// + public double MinValue { get; protected set; } + + /// + /// Gets or sets the maximum value of the dataset. + /// + public double MaxValue { get; protected set; } + + /// + /// Gets or sets the color axis. + /// + /// The color axis. + public IColorAxis ColorAxis { get; protected set; } + + /// + /// Gets or sets the color axis key. + /// + /// The color axis key. + public string ColorAxisKey { get; set; } + + /// + /// Renders the series on the specified render context. + /// + /// The rendering context. + public override void Render(IRenderContext rc) + { + if (this.Data == null) + { + this.image = null; + return; + } + + if (this.ImageSize > 0) + { + this.RenderFixed(rc, this.PlotModel); + } + else + { + this.RenderDynamic(rc, this.PlotModel); + } + } + + /// + /// Renders by an image sized from the available plot area. + /// + /// The rc. + /// The model. + public void RenderDynamic(IRenderContext rc, PlotModel model) + { + int m = this.Data.GetLength(0); + int n = this.Data.GetLength(1); + + // get the available plot area + var dest = model.PlotArea; + int width = (int)dest.Width; + int height = (int)dest.Height; + if (width == 0 || height == 0) + { + return; + } + + if (this.pixels == null || this.pixels.GetLength(0) != height || this.pixels.GetLength(1) != width) + { + this.pixels = new OxyColor[width, height]; + } + + var p = this.pixels; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + // transform from screen to magnitude/angle + var sp = new ScreenPoint(dest.Left + x, dest.Top + y); + var xy = this.InverseTransform(sp); + double angle; + double magnitude; + if (this.PlotModel.PlotType != PlotType.Polar) + { + angle = Math.Atan2(xy.Y, xy.X) / Math.PI * 180; + magnitude = Math.Sqrt((xy.X * xy.X) + (xy.Y * xy.Y)); + } + else + { + angle = xy.Y / Math.PI * 180; + magnitude = xy.X; + while (angle < 0) + { + angle += 360; + } + while (angle > 360) + { + angle -= 360; + } + } + + // transform to indices in the Data array + var ii = (angle - this.Angle0) / (this.Angle1 - this.Angle0) * m; + var jj = (magnitude - this.Magnitude0) / (this.Magnitude1 - this.Magnitude0) * n; + if (ii >= 0 && ii < m && jj >= 0 && jj < n) + { + // get the (interpolated) value + var value = this.GetValue(ii, jj); + + // use the color axis to get the color + p[x, y] = OxyColor.FromAColor(160, this.ColorAxis.GetColor(value)); + } + else + { + // outside the range of the Data array + p[x, y] = OxyColors.Transparent; + } + } + } + + // Create the PNG image + this.image = OxyImage.Create(p, ImageFormat.Png); + + // Render the image + rc.DrawImage(this.image, dest.Left, dest.Top, dest.Width, dest.Height, 1, false); + } + + /// + /// Refreshes the image next time the series is rendered. + /// + public void Refresh() + { + this.image = null; + } + + /// + /// Renders by scaling a fixed image. + /// + /// The render context. + /// The model. + public void RenderFixed(IRenderContext rc, PlotModel model) + { + if (image == null) + { + int m = this.Data.GetLength(0); + int n = this.Data.GetLength(1); + + int width = this.ImageSize; + int height = this.ImageSize; + if (this.pixels == null || this.pixels.GetLength(0) != height || this.pixels.GetLength(1) != width) + { + this.pixels = new OxyColor[width, height]; + } + + var p = this.pixels; + for (int yi = 0; yi < height; yi++) + { + for (int xi = 0; xi < width; xi++) + { + double x = (xi - width * 0.5) / (width * 0.5) * this.Magnitude1; + double y = -(yi - height * 0.5) / (height * 0.5) * this.Magnitude1; + + double angle = Math.Atan2(y, x) / Math.PI * 180; + double magnitude = Math.Sqrt(x * x + y * y); + + while (angle < 0) + { + angle += 360; + } + while (angle > 360) + { + angle -= 360; + } + + // transform to indices in the Data array + var ii = (angle - this.Angle0) / (this.Angle1 - this.Angle0) * m; + var jj = (magnitude - this.Magnitude0) / (this.Magnitude1 - this.Magnitude0) * n; + if (ii >= 0 && ii < m && jj >= 0 && jj < n) + { + // get the (interpolated) value + var value = this.GetValue(ii, jj); + + // use the color axis to get the color + p[xi, yi] = OxyColor.FromAColor(160, this.ColorAxis.GetColor(value)); + } + else + { + // outside the range of the Data array + p[xi, yi] = OxyColors.Transparent; + } + } + } + + // Create the PNG image + this.image = OxyImage.Create(p, ImageFormat.Png); + } + + OxyRect dest; + if (this.PlotModel.PlotType != PlotType.Polar) + { + var topleft = this.Transform(-this.Magnitude1, this.Magnitude1); + var bottomright = this.Transform(this.Magnitude1, -this.Magnitude1); + dest = new OxyRect(topleft.X, topleft.Y, bottomright.X - topleft.X, bottomright.Y - topleft.Y); + } + else + { + var top = this.Transform(this.Magnitude1, 90); + var bottom = this.Transform(this.Magnitude1, 270); + var left = this.Transform(this.Magnitude1, 180); + var right = this.Transform(this.Magnitude1, 0); + dest = new OxyRect(left.X, top.Y, right.X - left.X, bottom.Y - top.Y); + } + + // Render the image + rc.DrawImage(this.image, dest.Left, dest.Top, dest.Width, dest.Height, 1, false); + } + + /// + /// Gets the value at the specified data indices. + /// + /// The first index in the Data array. + /// The second index in the Data array. + /// The value. + protected virtual double GetValue(double ii, double jj) + { + if (!this.Interpolate) + { + var i = (int)Math.Floor(ii); + var j = (int)Math.Floor(jj); + return this.Data[i, j]; + } + + ii -= 0.5; + jj -= 0.5; + + // bi-linear interpolation http://en.wikipedia.org/wiki/Bilinear_interpolation + var r = (int)Math.Floor(ii); + var c = (int)Math.Floor(jj); + + int r0 = r > 0 ? r : 0; + int r1 = r + 1 < this.Data.GetLength(0) ? r + 1 : r; + int c0 = c > 0 ? c : 0; + int c1 = c + 1 < this.Data.GetLength(1) ? c + 1 : c; + + double v00 = this.Data[r0, c0]; + double v01 = this.Data[r0, c1]; + double v10 = this.Data[r1, c0]; + double v11 = this.Data[r1, c1]; + + double di = ii - r; + double dj = jj - c; + + double v0 = (v00 * (1 - dj)) + (v01 * dj); + double v1 = (v10 * (1 - dj)) + (v11 * dj); + + return (v0 * (1 - di)) + (v1 * di); + } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// A TrackerHitResult for the current hit. + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + return null; + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected override void EnsureAxes() + { + base.EnsureAxes(); + + this.ColorAxis = this.ColorAxisKey != null ? + this.PlotModel.GetAxis(this.ColorAxisKey) as IColorAxis : + this.PlotModel.DefaultColorAxis as IColorAxis; + } + + /// + /// Updates the maximum and minimum values of the series. + /// + protected override void UpdateMaxMin() + { + base.UpdateMaxMin(); + + this.MinValue = this.GetData().Min(); + this.MaxValue = this.GetData().Max(); + + //this.XAxis.Include(this.MinX); + //this.XAxis.Include(this.MaxX); + + //this.YAxis.Include(this.MinY); + //this.YAxis.Include(this.MaxY); + + var colorAxis = this.ColorAxis as Axis; + if (colorAxis != null) + { + colorAxis.Include(this.MinValue); + colorAxis.Include(this.MaxValue); + } + } + + /// + /// Gets the data as a sequence (LINQ-friendly). + /// + /// The sequence of data. + protected IEnumerable GetData() + { + int m = this.Data.GetLength(0); + int n = this.Data.GetLength(1); + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + yield return this.Data[i, j]; + } + } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Discussions/DiscussionExamples.cs b/Source/Examples/ExampleLibrary/Discussions/DiscussionExamples.cs new file mode 100644 index 0000000..b75dc85 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Discussions/DiscussionExamples.cs @@ -0,0 +1,371 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Globalization; + using System.Linq; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("Z0 Discussions")] + public class DiscussionExamples + { + [Example("#445576: Invisible contour series")] + public static PlotModel InvisibleContourSeries() + { + var model = new PlotModel { Title = "Invisible contour series" }; + var cs = new ContourSeries + { + IsVisible = false, + ColumnCoordinates = ArrayBuilder.CreateVector(-1, 1, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-1, 1, 0.05) + }; + cs.Data = ArrayBuilder.Evaluate((x, y) => x + y, cs.ColumnCoordinates, cs.RowCoordinates); + model.Series.Add(cs); + return model; + } + + [Example("#461507: StairStepSeries NullReferenceException")] + public static PlotModel StairStepSeries_NullReferenceException() + { + var plotModel1 = new PlotModel { Title = "StairStepSeries NullReferenceException" }; + plotModel1.Series.Add(new StairStepSeries()); + return plotModel1; + } + + [Example("#501409: Heatmap interpolation color")] + public static PlotModel HeatMapSeriesInterpolationColor() + { + var data = new double[2, 3]; + data[0, 0] = 10; + data[0, 1] = 0; + data[0, 2] = -10; + + var model = new PlotModel { Title = "HeatMapSeries" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = new OxyPalette(OxyColors.Red, OxyColors.Green, OxyColors.Blue) }); + + var hms = new HeatMapSeries + { + CoordinateDefinition = HeatMapCoordinateDefinition.Center, + X0 = 0, + X1 = 3, + Y0 = 0, + Y1 = 2, + Data = data, + Interpolate = false, + LabelFontSize = 0.2 + }; + model.Series.Add(hms); + return model; + } + + [Example("#522598: Peaks 400x400")] + public static PlotModel Peaks400() + { + return HeatMapSeriesExamples.CreatePeaks(null, true, 400); + } + + [Example("#474875: Updating HeatMapSeries 1")] + public static PlotModel UpdatingHeatMapSeries1() + { + var model = HeatMapSeriesExamples.CreatePeaks(); + model.Title = "Updating HeatMapSeries"; + model.Subtitle = "Click the heat map to change the Maximum of the color axis."; + var lca = (LinearColorAxis)model.Axes[0]; + var hms = (HeatMapSeries)model.Series[0]; + hms.MouseDown += (s, e) => + { + lca.Maximum = Double.IsNaN(lca.Maximum) ? 10 : Double.NaN; + model.InvalidatePlot(true); + }; + return model; + } + + [Example("#474875: Updating HeatMapSeries 2")] + public static PlotModel UpdatingHeatMapSeries() + { + var model = HeatMapSeriesExamples.CreatePeaks(); + model.Title = "Updating HeatMapSeries"; + model.Subtitle = "Click the heat map to change the Maximum of the color axis and invoke the Invalidate method on the HeatMapSeries."; + var lca = (LinearColorAxis)model.Axes[0]; + var hms = (HeatMapSeries)model.Series[0]; + hms.MouseDown += (s, e) => + { + lca.Maximum = Double.IsNaN(lca.Maximum) ? 10 : Double.NaN; + hms.Invalidate(); + model.InvalidatePlot(true); + }; + return model; + } + + [Example("#539104: Reduced color saturation")] + public static PlotModel ReducedColorSaturation() + { + var model = new PlotModel + { + Title = "Reduced color saturation", + }; + + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Bottom }); + + // modify the saturation of the default colors + model.DefaultColors = model.DefaultColors.Select(c => c.ChangeSaturation(0.5)).ToList(); + + var r = new Random(37); + for (var i = 0; i < model.DefaultColors.Count; i++) + { + var columnSeries = new BarSeries(); + columnSeries.Items.Add(new BarItem(50 + r.Next(50))); + columnSeries.Items.Add(new BarItem(40 + r.Next(50))); + model.Series.Add(columnSeries); + } + + return model; + } + + [Example("#539104: Medium intensity colors")] + public static PlotModel MediumIntensityColors() + { + var model = new PlotModel + { + Title = "Medium intensity colors", + }; + + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Bottom }); + + // See http://www.perceptualedge.com/articles/visual_business_intelligence/rules_for_using_color.pdf + model.DefaultColors = new[] + { + OxyColor.FromRgb(114, 114, 114), + OxyColor.FromRgb(241, 89, 95), + OxyColor.FromRgb(121, 195, 106), + OxyColor.FromRgb(89, 154, 211), + OxyColor.FromRgb(249, 166, 90), + OxyColor.FromRgb(158, 102, 171), + OxyColor.FromRgb(205, 112, 88), + OxyColor.FromRgb(215, 127, 179) + }; + + var r = new Random(37); + for (var i = 0; i < model.DefaultColors.Count; i++) + { + var columnSeries = new BarSeries(); + columnSeries.Items.Add(new BarItem(50 + r.Next(50))); + columnSeries.Items.Add(new BarItem(40 + r.Next(50))); + model.Series.Add(columnSeries); + } + + return model; + } + + [Example("#539104: Brewer colors (4)")] + public static PlotModel BrewerColors4() + { + var model = new PlotModel + { + Title = "Brewer colors (Accent scheme)", + }; + + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Bottom }); + + // See http://colorbrewer2.org/?type=qualitative&scheme=Accent&n=4 + model.DefaultColors = new[] + { + OxyColor.FromRgb(127, 201, 127), + OxyColor.FromRgb(190, 174, 212), + OxyColor.FromRgb(253, 192, 134), + OxyColor.FromRgb(255, 255, 153) + }; + + var r = new Random(37); + for (var i = 0; i < model.DefaultColors.Count; i++) + { + var columnSeries = new BarSeries(); + columnSeries.Items.Add(new BarItem(50 + r.Next(50))); + columnSeries.Items.Add(new BarItem(40 + r.Next(50))); + model.Series.Add(columnSeries); + } + + return model; + } + + [Example("#539104: Brewer colors (6)")] + public static PlotModel BrewerColors6() + { + var model = new PlotModel + { + Title = "Brewer colors (Paired scheme)", + }; + + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Bottom }); + + // See http://colorbrewer2.org/?type=qualitative&scheme=Paired&n=6 + model.DefaultColors = new[] + { + OxyColor.FromRgb(166, 206, 227), + OxyColor.FromRgb(31, 120, 180), + OxyColor.FromRgb(178, 223, 138), + OxyColor.FromRgb(51, 160, 44), + OxyColor.FromRgb(251, 154, 153), + OxyColor.FromRgb(227, 26, 28) + }; + + var r = new Random(37); + for (var i = 0; i < model.DefaultColors.Count; i++) + { + var columnSeries = new BarSeries(); + columnSeries.Items.Add(new BarItem(50 + r.Next(50))); + columnSeries.Items.Add(new BarItem(40 + r.Next(50))); + model.Series.Add(columnSeries); + } + + return model; + } + + [Example("#542701: Same color of LineSeries and axis title & labels")] + public static PlotModel SameColorOfLineSeriesAndAxisTitleAndLabels() + { + var model = new PlotModel { Title = "Same color of LineSeries and axis title & labels" }; + var color = OxyColors.IndianRed; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Axis 1", TitleColor = color, TextColor = color }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Series.Add(new LineSeries { Title = "LineSeries 1", Color = color, ItemsSource = new[] { new DataPoint(0, 0), new DataPoint(10, 3), new DataPoint(20, 2) } }); + return model; + } + + [Example("#549839: Polar plot with custom arrow series")] + public static PlotModel PolarPlotWithArrows() + { + var model = new PlotModel { Title = "Custom arrow series", PlotType = PlotType.Polar, PlotAreaBorderColor = OxyColors.Undefined }; + model.Axes.Add(new AngleAxis { Minimum = 0, Maximum = 360, MajorStep = 30, MinorStep = 30, MajorGridlineStyle = LineStyle.Dash }); + model.Axes.Add(new MagnitudeAxis { Minimum = 0, Maximum = 5, MajorStep = 1, MinorStep = 1, Angle = 90, MajorGridlineStyle = LineStyle.Dash }); + model.Series.Add(new ArrowSeries549839 { EndPoint = new DataPoint(1, 40) }); + model.Series.Add(new ArrowSeries549839 { EndPoint = new DataPoint(2, 75) }); + model.Series.Add(new ArrowSeries549839 { EndPoint = new DataPoint(3, 110) }); + model.Series.Add(new ArrowSeries549839 { EndPoint = new DataPoint(4, 140) }); + model.Series.Add(new ArrowSeries549839 { EndPoint = new DataPoint(5, 180) }); + return model; + } + + [Example("MarkerType = Circle problem")] + public static PlotModel MarkerTypeCircleProblem() + { + var plotModel = new PlotModel { PlotType = PlotType.Cartesian, PlotAreaBorderThickness = new OxyThickness(0) }; + + var l = new Legend + { + LegendSymbolLength = 30 + }; + + var xaxis = new DateTimeAxis + { + Position = AxisPosition.Bottom, + TickStyle = TickStyle.None, + AxislineStyle = LineStyle.Solid, + AxislineColor = OxyColor.FromRgb(153, 153, 153), + StringFormat = CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(1) + "d HH", + IntervalType = DateTimeIntervalType.Hours + }; + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0.001f, + Maximum = 3, + MajorGridlineStyle = LineStyle.Solid, + TickStyle = TickStyle.None, + IntervalLength = 50 + }; + + plotModel.Axes.Add(xaxis); + plotModel.Axes.Add(yaxis); + + var series1 = new LineSeries + { + Color = OxyColor.FromRgb(44, 169, 173), + StrokeThickness = 1, + MarkerType = MarkerType.Circle, + MarkerStroke = OxyColors.Blue, + MarkerFill = OxyColors.SkyBlue, + // MarkerStrokeThickness = 5, + MarkerSize = 2, + DataFieldX = "Date", + DataFieldY = "Value", + TrackerFormatString = "Date: {2:d HH} Value: {4}" + }; + + series1.Points.Add(new DataPoint(0.1, 0.7)); + series1.Points.Add(new DataPoint(0.6, 0.9)); + series1.Points.Add(new DataPoint(1.0, 0.85)); + series1.Points.Add(new DataPoint(1.4, 0.95)); + series1.Points.Add(new DataPoint(1.8, 1.2)); + series1.Points.Add(new DataPoint(2.2, 1.7)); + series1.Points.Add(new DataPoint(2.6, 1.7)); + series1.Points.Add(new DataPoint(3.0, 0.7)); + + plotModel.Series.Add(series1); + + return plotModel; + } + + private class ArrowSeries549839 : XYAxisSeries + { + private OxyColor defaultColor; + + public ArrowSeries549839() + { + this.Color = OxyColors.Automatic; + this.StrokeThickness = 2; + } + + public DataPoint StartPoint { get; set; } + + public DataPoint EndPoint { get; set; } + + public OxyColor Color { get; set; } + + public double StrokeThickness { get; set; } + + protected override void SetDefaultValues() + { + if (this.Color.IsAutomatic()) + { + this.defaultColor = this.PlotModel.GetDefaultColor(); + } + } + + public OxyColor ActualColor + { + get + { + return this.Color.GetActualColor(this.defaultColor); + } + } + + public override void Render(IRenderContext rc) + { + // transform to screen coordinates + var p0 = this.Transform(this.StartPoint); + var p1 = this.Transform(this.EndPoint); + + var direction = p1 - p0; + var normal = new ScreenVector(direction.Y, -direction.X); + + // the end points of the arrow head, scaled by length of arrow + var p2 = p1 - (direction * 0.2) + (normal * 0.1); + var p3 = p1 - (direction * 0.2) - (normal * 0.1); + + // draw the line segments + rc.DrawLineSegments(new[] { p0, p1, p1, p2, p1, p3 }, this.ActualColor, this.StrokeThickness, this.EdgeRenderingMode); + } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Example.cs b/Source/Examples/ExampleLibrary/Example.cs new file mode 100644 index 0000000..26c3fdc --- /dev/null +++ b/Source/Examples/ExampleLibrary/Example.cs @@ -0,0 +1,43 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + + /// + /// Represents an example. + /// + public class Example + { + /// + /// Initializes a new instance of the class. + /// + /// The model. + /// The controller. + public Example(PlotModel model, IPlotController controller = null) + { + this.Model = model; + this.Controller = controller; + } + + /// + /// Gets the controller. + /// + /// + /// The controller. + /// + public IPlotController Controller { get; private set; } + + /// + /// Gets the model. + /// + /// + /// The model. + /// + public PlotModel Model { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/ExampleFlags.cs b/Source/Examples/ExampleLibrary/ExampleFlags.cs new file mode 100644 index 0000000..16e24d9 --- /dev/null +++ b/Source/Examples/ExampleLibrary/ExampleFlags.cs @@ -0,0 +1,27 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + /// + /// Properties of an example. + /// + [Flags] + public enum ExampleFlags + { + /// + /// Transpose the axes, so that horizontal axes become vertical and vice versa. + /// + Transpose = 1, + + /// + /// Reverse the axes, so that their start and end positions are mirrored within the plot area. + /// + Reverse = 2, + } +} diff --git a/Source/Examples/ExampleLibrary/ExampleInfo.cs b/Source/Examples/ExampleLibrary/ExampleInfo.cs new file mode 100644 index 0000000..15c694f --- /dev/null +++ b/Source/Examples/ExampleLibrary/ExampleInfo.cs @@ -0,0 +1,313 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + using ExampleLibrary.Utilities; + + using OxyPlot; + + /// + /// Provides information about an example. + /// + public class ExampleInfo + { + /// + /// The method to invoke. + /// + private readonly MethodInfo method; + + /// + /// Indicates whether this instance was already initialized. + /// + private bool initialized; + + /// + /// The un-modified example. + /// + private Example Example; + + /// + /// The examples for this example info. + /// + private Dictionary examples; + + /// + /// The options supported by this example. + /// + private ExampleFlags exampleSupport; + + /// + /// Initializes a new instance of the class. + /// + /// The category. + /// The title. + /// The tags. + /// The method. + /// A value indiciating whether the example should be excluded from automated tests. + public ExampleInfo(string category, string title, string[] tags, MethodInfo method, bool excludeFromAutomatedTests) + { + this.Category = category; + this.Title = title; + this.Tags = tags; + this.method = method; + this.ExcludeFromAutomatedTests = excludeFromAutomatedTests; + } + + /// + /// Gets the category. + /// + /// + /// The category. + /// + public string Category { get; } + + /// + /// Gets the code. + /// + /// + /// The code. + /// + public string Code => this.PlotModel?.ToCode(); + + /// + /// Gets a value indicating whether the plot model is reversible. + /// + public bool IsReversible + { + get + { + this.EnsureInitialized(); + return exampleSupport.HasFlag(ExampleFlags.Reverse); + } + } + + /// + /// Gets a value indicating whether the plot model is transposable. + /// + public bool IsTransposable + { + get + { + this.EnsureInitialized(); + return exampleSupport.HasFlag(ExampleFlags.Transpose); + } + } + + /// + /// Gets the code for the example with the given flags. + /// + /// The flags for the example. + /// Code that produces the example. + /// Ignores unsupported flags. + public string GetCode(ExampleFlags flags) + { + return this.GetModel(flags)?.ToCode(); + } + + /// + /// Gets the for the example with the given flags. + /// + /// The flags for the example. + /// The . + /// Ignores unsupported flags. + public PlotModel GetModel(ExampleFlags flags) + { + return this.GetExample(flags).Model; + } + + /// + /// Gets the for the example with the given flags. + /// + /// The flags for the example. + /// The . + /// Ignores unsupported flags. + public IPlotController GetController(ExampleFlags flags) + { + return this.GetExample(flags).Controller; + } + + /// + /// Gets the with the given flags. + /// + /// The flags for the example. + /// The . + /// Ignores unsupported flags. + private Example GetExample(ExampleFlags flags) + { + this.EnsureInitialized(); + + // ignore flags we don't support + flags = FilterFlags(flags); + + if (!examples.TryGetValue(flags, out var example)) + { + example = GetDefaultExample(); + + if (flags.HasFlag(ExampleFlags.Transpose)) + { + example.Model.Transpose(); + } + + if (flags.HasFlag(ExampleFlags.Reverse)) + { + example.Model.ReverseAllAxes(); + } + + examples[flags] = example; + } + + return example; + } + + /// + /// Gets the plot controller for the default example. + /// + /// + /// The plot controller. + /// + public IPlotController PlotController + { + get + { + this.EnsureInitialized(); + return this.Example.Controller; + } + } + + /// + /// Gets the plot model for the default example. + /// + /// + /// The plot model. + /// + public PlotModel PlotModel + { + get + { + this.EnsureInitialized(); + return this.Example.Model; + } + } + + /// + /// Gets the tags. + /// + /// + /// The tags. + /// + public string[] Tags { get; } + + /// + /// Gets a value indiciating whether this example should be excluded from automated tests. + /// + /// + /// true if the example should be excluded from automated tests, otherwise false. + /// + public bool ExcludeFromAutomatedTests { get; } + + /// + /// Gets the title. + /// + /// + /// The title. + /// + public string Title { get; } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return this.Title; + } + + /// + /// Prepares from the given parameters. + /// + /// Whether to set the flag. + /// Whether to set the flag. + /// The . + public static ExampleFlags PrepareFlags(bool transpose, bool reverse) + { + var flags = (ExampleFlags)0; + + if (transpose) + { + flags |= ExampleFlags.Transpose; + } + + if (reverse) + { + flags |= ExampleFlags.Reverse; + } + + return flags; + } + + /// + /// Initializes this instance if it is not already initialized. + /// + private void EnsureInitialized() + { + if (this.initialized) + { + return; + } + + this.initialized = true; + this.examples = new Dictionary(); + + this.Example = GetDefaultExample(); + + this.exampleSupport = PrepareFlags(this.Example.Model?.IsTransposable() == true, this.Example.Model?.IsReversible() == true); + + // remember the 'default' model: loads the transposed/reversed ones as we need them + this.examples.Add(PrepareFlags(false, false), this.Example); + } + + /// + /// Gets a new instance of the default example. + /// + /// An . + private Example GetDefaultExample() + { + var result = this.method.Invoke(null, null); + + if (result is null) + { + return new Example(null, null); + } + if (result is PlotModel plotModel) + { + return new Example(plotModel, null); + } + else if (result is Example example) + { + return example; + } + + throw new Exception($"Unsupport type returned by example method for example {Category} > {Title}: {result.GetType().FullName}."); + } + + /// + /// Filters unsupported flags from the given flags. + /// + /// The original set of flags. + /// The filtered flags. + private ExampleFlags FilterFlags(ExampleFlags flags) + { + return flags & exampleSupport; + } + } +} diff --git a/Source/Examples/ExampleLibrary/ExampleLibrary.csproj b/Source/Examples/ExampleLibrary/ExampleLibrary.csproj new file mode 100644 index 0000000..d00de2b --- /dev/null +++ b/Source/Examples/ExampleLibrary/ExampleLibrary.csproj @@ -0,0 +1,30 @@ + + + netstandard2.0;net462;net6.0;net7.0 + OxyPlot.ExampleLibrary + true + Example models for OxyPlot. + plotting plot charting chart + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/ExampleLibrary.snk b/Source/Examples/ExampleLibrary/ExampleLibrary.snk new file mode 100644 index 0000000..9dadbd1 Binary files /dev/null and b/Source/Examples/ExampleLibrary/ExampleLibrary.snk differ diff --git a/Source/Examples/ExampleLibrary/Examples.cs b/Source/Examples/ExampleLibrary/Examples.cs new file mode 100644 index 0000000..a93ba99 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples.cs @@ -0,0 +1,104 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + /// + /// Enumerates all examples in the assembly. + /// + public static class Examples + { + /// + /// Gets all examples in the specified category. + /// + /// The type of the category. + public static IEnumerable GetCategory(Type categoryType) + { + var typeInfo = categoryType.GetTypeInfo(); + var examplesAttribute = typeInfo.GetCustomAttributes().FirstOrDefault(); + var examplesTags = typeInfo.GetCustomAttributes().FirstOrDefault() ?? new TagsAttribute(); + + var types = new List(); + var baseType = typeInfo; + while (baseType != null) + { + types.Add(baseType.AsType()); + baseType = baseType.BaseType?.GetTypeInfo(); + } + + foreach (var t in types) + { + foreach (var method in t.GetRuntimeMethods()) + { + var exampleAttribute = method.GetCustomAttributes().FirstOrDefault(); + if (exampleAttribute != null) + { + var exampleTags = method.GetCustomAttributes().FirstOrDefault() ?? new TagsAttribute(); + var tags = new List(examplesTags.Tags); + tags.AddRange(exampleTags.Tags); + yield return + new ExampleInfo( + examplesAttribute.Category, + exampleAttribute.Title, + tags.ToArray(), + method, + exampleAttribute.ExcludeFromAutomatedTests); + } + } + } + } + + /// + /// Gets all examples. + /// + public static IEnumerable GetList() + { + foreach (var type in typeof(Examples).GetTypeInfo().Assembly.DefinedTypes) + { + if (!type.GetCustomAttributes().Any()) + { + continue; + } + + foreach (var example in GetCategory(type.AsType())) + { + yield return example; + } + } + } + + /// + /// Gets all examples suitable for automated test. + /// + public static IEnumerable GetListForAutomatedTest() + { + return GetList().Where(ex => !ex.ExcludeFromAutomatedTests); + } + + /// + /// Gets the first example of each category suitable for automated test. + /// + public static IEnumerable GetFirstExampleOfEachCategoryForAutomatedTest() + { + return GetListForAutomatedTest() + .GroupBy(example => example.Category) + .Select(group => group.First()); + } + + /// + /// Gets the 'rendering capabilities' examples suitable for automated test. + /// + public static IEnumerable GetRenderingCapabilitiesForAutomatedTest() + { + return GetCategory(typeof(RenderingCapabilities)).Where(ex => !ex.ExcludeFromAutomatedTests); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/FilteringExamples.cs b/Source/Examples/ExampleLibrary/Examples/FilteringExamples.cs new file mode 100644 index 0000000..f28a699 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/FilteringExamples.cs @@ -0,0 +1,151 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("Filtering data points")] + public static class FilteringExamples + { + [Example("Filtering NaN points")] + public static PlotModel FilteringInvalidPoints() + { + var plot = new PlotModel { Title = "Filtering NaN points" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var ls1 = new LineSeries(); + ls1.Points.Add(new DataPoint(double.NaN, double.NaN)); + ls1.Points.Add(new DataPoint(1, 0)); + ls1.Points.Add(new DataPoint(2, 10)); + ls1.Points.Add(new DataPoint(double.NaN, 20)); + ls1.Points.Add(new DataPoint(3, 10)); + ls1.Points.Add(new DataPoint(4, 0)); + ls1.Points.Add(new DataPoint(4.5, double.NaN)); + ls1.Points.Add(new DataPoint(5, 0)); + ls1.Points.Add(new DataPoint(7, 7)); + ls1.Points.Add(new DataPoint(double.NaN, double.NaN)); + ls1.Points.Add(new DataPoint(double.NaN, double.NaN)); + ls1.Points.Add(new DataPoint(7, 0)); + ls1.Points.Add(new DataPoint(double.NaN, double.NaN)); + plot.Series.Add(ls1); + + return plot; + } + + [Example("Filtering NaN points with AreaSeries")] + public static PlotModel FilteringInvalidPointsAreaSeries() + { + var plot = new PlotModel { Title = "Filtering NaN points in an AreaSeries" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var as1 = new AreaSeries(); + as1.Points.Add(new DataPoint(1, 0)); + as1.Points.Add(new DataPoint(2, 10)); + as1.Points.Add(new DataPoint(3, 10)); + as1.Points.Add(new DataPoint(4, 0)); + as1.Points.Add(new DataPoint(5, 0)); + as1.Points.Add(new DataPoint(6, 7)); + as1.Points.Add(new DataPoint(7, 7)); + as1.Points.Add(new DataPoint(double.NaN, double.NaN)); + as1.Points.Add(new DataPoint(double.NaN, double.NaN)); + as1.Points.Add(new DataPoint(8, 0)); + as1.Points.Add(new DataPoint(9, 0)); + as1.Points.Add(new DataPoint(double.NaN, double.NaN)); + + as1.Points2.Add(new DataPoint(1, 10)); + as1.Points2.Add(new DataPoint(2, 110)); + as1.Points2.Add(new DataPoint(3, 110)); + as1.Points2.Add(new DataPoint(4, 10)); + as1.Points2.Add(new DataPoint(5, 10)); + as1.Points2.Add(new DataPoint(6, 17)); + as1.Points2.Add(new DataPoint(7, 17)); + as1.Points2.Add(new DataPoint(double.NaN, double.NaN)); + as1.Points2.Add(new DataPoint(double.NaN, double.NaN)); + as1.Points2.Add(new DataPoint(8, 10)); + as1.Points2.Add(new DataPoint(9, 10)); + as1.Points2.Add(new DataPoint(double.NaN, double.NaN)); + + plot.Series.Add(as1); + + return plot; + } + + + [Example("Filtering undefined points")] + public static PlotModel FilteringUndefinedPoints() + { + var plot = new PlotModel { Title = "Filtering undefined points" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var ls1 = new LineSeries(); + ls1.Points.Add(DataPoint.Undefined); + ls1.Points.Add(new DataPoint(1, 0)); + ls1.Points.Add(new DataPoint(2, 10)); + ls1.Points.Add(DataPoint.Undefined); + ls1.Points.Add(new DataPoint(3, 10)); + ls1.Points.Add(new DataPoint(4, 0)); + ls1.Points.Add(DataPoint.Undefined); + ls1.Points.Add(new DataPoint(5, 0)); + ls1.Points.Add(new DataPoint(7, 7)); + ls1.Points.Add(DataPoint.Undefined); + ls1.Points.Add(DataPoint.Undefined); + ls1.Points.Add(new DataPoint(7, 0)); + ls1.Points.Add(DataPoint.Undefined); + plot.Series.Add(ls1); + + return plot; + } + + [Example("Filtering invalid points (log axis)")] + public static PlotModel FilteringInvalidPointsLog() + { + var plot = new PlotModel { Title = "Filtering invalid points on logarithmic axes" }; + plot.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom }); + plot.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left }); + + var ls = new LineSeries(); + ls.Points.Add(new DataPoint(double.NaN, double.NaN)); + ls.Points.Add(new DataPoint(1, 1)); + ls.Points.Add(new DataPoint(10, 10)); + ls.Points.Add(new DataPoint(0, 20)); + ls.Points.Add(new DataPoint(100, 2)); + ls.Points.Add(new DataPoint(1000, 12)); + ls.Points.Add(new DataPoint(4.5, 0)); + ls.Points.Add(new DataPoint(10000, 4)); + ls.Points.Add(new DataPoint(100000, 14)); + ls.Points.Add(new DataPoint(double.NaN, double.NaN)); + ls.Points.Add(new DataPoint(1000000, 5)); + ls.Points.Add(new DataPoint(double.NaN, double.NaN)); + plot.Series.Add(ls); + return plot; + } + + [Example("Filtering points outside (-1,1)")] + public static PlotModel FilteringPointsOutsideRange() + { + var plot = new PlotModel { Title = "Filtering points outside (-1,1)" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, FilterMinValue = -1, FilterMaxValue = 1 }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, FilterMinValue = -1, FilterMaxValue = 1 }); + + var ls = new LineSeries(); + for (double i = 0; i < 200; i += 0.01) + { + ls.Points.Add(new DataPoint(0.01 * i * Math.Sin(i), 0.01 * i * Math.Cos(i))); + } + + plot.Series.Add(ls); + return plot; + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Examples/ItemsSourceExamples.cs b/Source/Examples/ExampleLibrary/Examples/ItemsSourceExamples.cs new file mode 100644 index 0000000..9e4f313 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/ItemsSourceExamples.cs @@ -0,0 +1,159 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Evaluates a chaotic function. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Series; + + [Examples("ItemsSource")] + public class ItemsSourceExamples + { + private static int n = 100000; + [Example("List")] + public static PlotModel UsingIDataPoint() + { + var points = new List(n); + for (int i = 0; i < n; i++) + { + var x = (double)i / (n - 1); + points.Add(new DataPoint(x, y(x))); + } + + var model = new PlotModel { Title = "Using IDataPoint" }; + model.Series.Add(new LineSeries { ItemsSource = points }); + return model; + } + + [Example("Items implementing IDataPointProvider")] + public static PlotModel UsingIDataPointProvider() + { + var points = new List(n); + for (int i = 0; i < n; i++) + { + var x = (double)i / (n - 1); + points.Add(new PointType1(x, y(x))); + } + + var model = new PlotModel { Title = "Items implementing IDataPointProvider" }; + model.Series.Add(new LineSeries { ItemsSource = points }); + return model; + } + + [Example("Mapping property")] + public static PlotModel UsingMappingProperty() + { + var points = new List(n); + for (int i = 0; i < n; i++) + { + var x = (double)i / (n - 1); + points.Add(new PointType2(x, y(x))); + } + + var model = new PlotModel { Title = "Using Mapping property" }; + model.Series.Add( + new LineSeries + { + ItemsSource = points, + Mapping = item => new DataPoint(((PointType2)item).Abscissa, ((PointType2)item).Ordinate) + }); + return model; + } + + [Example("Using reflection (slow)")] + public static PlotModel UsingReflection() + { + var points = new List(n); + for (int i = 0; i < n; i++) + { + var x = (double)i / (n - 1); + points.Add(new PointType2(x, y(x))); + } + + var model = new PlotModel { Title = "Using reflection (slow)" }; + model.Series.Add(new LineSeries { ItemsSource = points, DataFieldX = "Abscissa", DataFieldY = "Ordinate" }); + return model; + } + + [Example("Using reflection with path (slow)")] + public static PlotModel UsingReflectionPath() + { + var points = new List(n); + for (int i = 0; i < n; i++) + { + var x = (double)i / (n - 1); + points.Add(new ItemType3(x, y(x))); + } + + var model = new PlotModel { Title = "Using reflection with path (slow)" }; + model.Series.Add(new LineSeries { ItemsSource = points, DataFieldX = "Point.X", DataFieldY = "Point.Y" }); + return model; + } + + private class PointType1 : IDataPointProvider, ICodeGenerating + { + public PointType1(double abscissa, double ordinate) + { + this.Abscissa = abscissa; + this.Ordinate = ordinate; + } + + public double Abscissa { get; private set; } + + public double Ordinate { get; private set; } + + public DataPoint GetDataPoint() + { + return new DataPoint(Abscissa, Ordinate); + } + + public string ToCode() + { + return CodeGenerator.FormatConstructor(this.GetType(), "{0},{1}", this.Abscissa, this.Ordinate); + } + } + + private class PointType2 + { + public PointType2(double abscissa, double ordinate) + { + this.Abscissa = abscissa; + this.Ordinate = ordinate; + } + + public double Abscissa { get; private set; } + + public double Ordinate { get; private set; } + } + + private class ItemType3 + { + public ItemType3(double x, double y) + { + this.Point = new ScreenPoint(x, y); + } + + public ScreenPoint Point { get; private set; } + } + + /// + /// Evaluates a chaotic function. + /// + /// The x value. + /// A y value. + private static double y(double x) + { + // http://computing.dcu.ie/~humphrys/Notes/Neural/chaos.html + return Math.Sin(3 / x) * Math.Sin(5 / (1 - x)); + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Examples/LegendExamples.cs b/Source/Examples/ExampleLibrary/Examples/LegendExamples.cs new file mode 100644 index 0000000..93b7e0d --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/LegendExamples.cs @@ -0,0 +1,496 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("Legends")] + public static class LegendExamples + { + [Example("Legend at right top inside")] + public static PlotModel LegendRightTopInside() + { + var model = CreateModel(); + var l = new Legend + { + LegendPlacement = LegendPlacement.Inside, + LegendPosition = LegendPosition.RightTop, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + + return model; + } + + [Example("Legend at right top outside")] + public static PlotModel LegendRightTopOutside() + { + var model = CreateModel(); + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.RightTop, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Legend at BottomLeft outside horizontal")] + public static PlotModel LegendBottomLeftHorizontal() + { + var model = CreateModel(4); + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomLeft, + LegendOrientation = LegendOrientation.Horizontal, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Legend at TopLeft outside vertical")] + public static PlotModel LegendTopLeftVertical() + { + var model = CreateModel(4); + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.TopLeft, + LegendOrientation = LegendOrientation.Vertical, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + + return model; + } + + [Example("Legend at default position")] + public static PlotModel LegendDefault() + { + var model = CreateModel(); + var l = new Legend(); + + model.Legends.Add(l); + + return model; + } + + [Example("LegendItemSpacing (only for horizontal orientation)")] + public static PlotModel LegendItemSpacing() + { + var model = CreateModel(); + var l = new Legend + { + LegendItemSpacing = 100, + LegendPosition = LegendPosition.BottomLeft, + LegendOrientation = LegendOrientation.Horizontal, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + + return model; + } + + [Example("LegendLineSpacing (vertical legend orientation)")] + public static PlotModel LegendLineSpacingVertical() + { + var model = CreateModel(); + var l = new Legend + { + LegendLineSpacing = 30, + LegendPosition = LegendPosition.TopLeft, + LegendOrientation = LegendOrientation.Vertical, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("LegendLineSpacing (horizontal legend orientation)")] + public static PlotModel LegendLineSpacingHorizontal() + { + var model = CreateModel(); + var l = new Legend + { + LegendLineSpacing = 30, + LegendPosition = LegendPosition.TopLeft, + LegendOrientation = LegendOrientation.Horizontal, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("LegendColumnSpacing (only for vertical orientation)")] + public static PlotModel LegendColumnSpacing() + { + var model = CreateModel(60); + var l = new Legend + { + LegendColumnSpacing = 100, + LegendPosition = LegendPosition.TopRight, + LegendOrientation = LegendOrientation.Vertical, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Hidden Legend")] + public static PlotModel LegendHidden() + { + var model = CreateModel(); + var l = new Legend + { + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + model.Legends.Add(l); + + model.IsLegendVisible = false; + return model; + } + + [Example("Grayscale colors")] + public static PlotModel LegendGrayscale() + { + var model = CreateModel(); + model.DefaultColors = new List { OxyColors.Black, OxyColors.Gray }; + var l = new Legend + { + LegendSymbolLength = 32, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Clipped legends")] + public static PlotModel ClippedLegends() + { + var model = CreateModel(1); + model.Series[0].Title = "1234567890 abcdefghijklmnopqrstuvwxyzæøå ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ 1234567890 abcdefghijklmnopqrstuvwxyzæøå ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"; + var l = new Legend + { + LegendPlacement = LegendPlacement.Inside, + LegendPosition = LegendPosition.RightTop, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Clipped legends RightTop outside with MaxWidth")] + public static PlotModel ClippedLegendsOutside() + { + var model = ClippedLegends(); + model.Legends[0].LegendPlacement = LegendPlacement.Outside; + model.Legends[0].LegendPosition = LegendPosition.RightTop; + model.Legends[0].LegendMaxWidth = 200; + + return model; + } + + [Example("Clipped legends TopRight outside")] + public static PlotModel ClippedLegendsRight() + { + var model = ClippedLegends(); + model.Legends[0].LegendPlacement = LegendPlacement.Outside; + model.Legends[0].LegendPosition = LegendPosition.TopRight; + + return model; + } + + [Example("LegendMaxHeight (vertical legend orientation)")] + public static PlotModel LegendBottomCenterOutsideWithMaxHeight() + { + var model = CreateModel(); + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Vertical, + LegendMaxHeight = 75.0, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Legend with DefaultFontSize")] + public static PlotModel LegendDefaultFontSize() + { + var model = CreateModel(); + var l = new Legend + { + LegendFontSize = double.NaN, + LegendTitle = "Title in DefaultFontSize", + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + model.DefaultFontSize = 20; + return model; + } + + [Example("Legend with grouped Series Horizontal")] + public static PlotModel SingleLegendWithSeriesGroupsHorizontal() + { + var model = CreateModel(21); + for (int i = 0; i < 7; i++) + model.Series[i].SeriesGroupName = "group 1"; + for (int i = 7; i < 14; i++) + model.Series[i].SeriesGroupName = "group 2"; + for (int i = 14; i < 21; i++) + model.Series[i].SeriesGroupName = "group 3"; + + var l = new Legend + { + LegendFontSize = double.NaN, + LegendTitle = "Legend with groups of Series", + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + GroupNameFont="Segoe UI Black", + LegendPosition = LegendPosition.TopLeft, + LegendOrientation = LegendOrientation.Horizontal + }; + + model.Legends.Add(l); + return model; + } + + [Example("Legend with grouped Series")] + public static PlotModel SingleLegendWithSeriesGroups() + { + var model = CreateModel(21); + for (int i = 0; i < 7; i++) + model.Series[i].SeriesGroupName = "group 1"; + for (int i = 7; i < 14; i++) + model.Series[i].SeriesGroupName = "group 2"; + for (int i = 14; i < 21; i++) + model.Series[i].SeriesGroupName = "group 3"; + + var l = new Legend + { + LegendFontSize = double.NaN, + LegendTitle = "Legend with groups of Series", + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l); + return model; + } + + [Example("Legend with grouped Series and MaxHeight")] + public static PlotModel SingleLegendWithSeriesGroupsMaxHeight() + { + var model = CreateModel(21); + for (int i = 0; i < 7; i++) + model.Series[i].SeriesGroupName = "group 1"; + for (int i = 7; i < 14; i++) + model.Series[i].SeriesGroupName = "group 2"; + for (int i = 14; i < 21; i++) + model.Series[i].SeriesGroupName = "group 3"; + + var l = new Legend + { + LegendFontSize = double.NaN, + LegendTitle = "Legend with groups of Series", + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + LegendMaxHeight = 275.0 + }; + + model.Legends.Add(l); + return model; + } + + [Example("Multiple Legends with grouped Series")] + public static PlotModel MultipleLegendsWithSeriesGroups() + { + var model = CreateModel(21); + for (int i = 0; i < 7; i++) + { + model.Series[i].SeriesGroupName = "group 1"; + model.Series[i].LegendKey = "Legend 1"; + } + for (int i = 7; i < 14; i++) + { + model.Series[i].SeriesGroupName = "group 2"; + model.Series[i].LegendKey = "Legend 1"; + } + for (int i = 14; i < 21; i++) + { + model.Series[i].SeriesGroupName = "group 3"; + model.Series[i].LegendKey = "Legend 2"; + } + + var l1 = new Legend + { + Key="Legend 1", + LegendFontSize = double.NaN, + LegendTitle = "Legend 1 Series", + LegendPlacement = LegendPlacement.Inside, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + var l2 = new Legend + { + Key = "Legend 2", + LegendFontSize = double.NaN, + LegendTitle = "Legend 2 Series", + LegendPlacement = LegendPlacement.Outside, + LegendBackground = OxyColor.FromAColor(200, OxyColors.White), + LegendBorder = OxyColors.Black, + }; + + model.Legends.Add(l1); + model.Legends.Add(l2); + return model; + } + + [Example("Full width legend")] + public static PlotModel LegendFullWidth() + { + var model = CreateModel(21); + + var l1 = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.TopCenter, + LegendOrientation = LegendOrientation.Horizontal, + AllowUseFullExtent = true, + }; + + var l2 = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + AllowUseFullExtent = true, + }; + + model.PlotMargins = new OxyThickness(50); + + model.Legends.Add(l1); + model.Legends.Add(l2); + + model.InvalidatePlot(true); + + return model; + } + + [Example("Full height legend")] + public static PlotModel LegendFullHeight() + { + var model = CreateModel(21); + + var l1 = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.LeftTop, + LegendOrientation = LegendOrientation.Vertical, + AllowUseFullExtent = true, + }; + + var l2 = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.RightTop, + LegendOrientation = LegendOrientation.Vertical, + AllowUseFullExtent = true, + }; + + model.Legends.Add(l1); + model.Legends.Add(l2); + + return model; + } + + [Example("Legend showing invisible series")] + public static PlotModel LegendShowingInivisbleSeries() + { + return CreateModelWithInivisbleSeries(true); + } + + [Example("Legend not showing invisible series")] + public static PlotModel LegendNotShowingInivisbleSeries() + { + return CreateModelWithInivisbleSeries(false); + } + + private static PlotModel CreateModelWithInivisbleSeries(bool showInvisibleSeries) + { + var model = CreateModel(); + var l = new Legend() + { + ShowInvisibleSeries = showInvisibleSeries, + }; + + model.Legends.Add(l); + + for (int i = 0; i < model.Series.Count; i += 2) + { + model.Series[i].IsVisible = false; + } + + model.InvalidatePlot(false); + return model; + } + + private static PlotModel CreateModel(int n = 20) + { + var model = new PlotModel { Title = "LineSeries" }; + + for (int i = 1; i <= n; i++) + { + var s = new LineSeries { Title = "Series " + i }; + model.Series.Add(s); + for (double x = 0; x < 2 * Math.PI; x += 0.1) + { + s.Points.Add(new DataPoint(x, (Math.Sin(x * i) / i) + i)); + } + } + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/MouseEventExamples.cs b/Source/Examples/ExampleLibrary/Examples/MouseEventExamples.cs new file mode 100644 index 0000000..74f5379 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/MouseEventExamples.cs @@ -0,0 +1,661 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Reflection; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("Mouse Events")] + public class MouseEventExamples + { + [Example("PlotModel mouse events")] + public static PlotModel MouseEvents() + { + var model = new PlotModel { Title = "Mouse events", Subtitle = "Left click and drag" }; + var yaxis = new LinearAxis { Position = AxisPosition.Left, Minimum = -1, Maximum = 1 }; + var xaxis = new LinearAxis { Position = AxisPosition.Bottom, Minimum = -1, Maximum = 1 }; + model.Axes.Add(yaxis); + model.Axes.Add(xaxis); + + LineSeries s1 = null; + + // Subscribe to the mouse down event on the line series + model.MouseDown += (s, e) => + { + // only handle the left mouse button (right button can still be used to pan) + if (e.ChangedButton == OxyMouseButton.Left) + { + // Add a line series + s1 = new LineSeries + { + Title = "LineSeries" + (model.Series.Count + 1), + MarkerType = MarkerType.None, + StrokeThickness = 2 + }; + s1.Points.Add(xaxis.InverseTransform(e.Position.X, e.Position.Y, yaxis)); + model.Series.Add(s1); + model.InvalidatePlot(false); + e.Handled = true; + } + }; + + model.MouseMove += (s, e) => + { + if (s1 != null) + { + s1.Points.Add(xaxis.InverseTransform(e.Position.X, e.Position.Y, yaxis)); + model.InvalidatePlot(false); + e.Handled = true; + } + }; + + model.MouseUp += (s, e) => + { + if (s1 != null) + { + s1 = null; + e.Handled = true; + } + }; + return model; + } + + [Example("MouseDown event and HitTestResult")] + public static PlotModel MouseDownEventHitTestResult() + { + var model = new PlotModel { Title = "MouseDown HitTestResult", Subtitle = "Reports the index of the nearest point." }; + + var s1 = new LineSeries(); + s1.Points.Add(new DataPoint(0, 10)); + s1.Points.Add(new DataPoint(10, 40)); + s1.Points.Add(new DataPoint(40, 20)); + s1.Points.Add(new DataPoint(60, 30)); + model.Series.Add(s1); + s1.MouseDown += (s, e) => + { + model.Subtitle = "Index of nearest point in LineSeries: " + Math.Round(e.HitTestResult.Index); + model.InvalidatePlot(false); + }; + + var s2 = new ScatterSeries(); + s2.Points.Add(new ScatterPoint(0, 15)); + s2.Points.Add(new ScatterPoint(10, 45)); + s2.Points.Add(new ScatterPoint(40, 25)); + s2.Points.Add(new ScatterPoint(60, 35)); + model.Series.Add(s2); + s2.MouseDown += (s, e) => + { + model.Subtitle = "Index of nearest point in ScatterSeries: " + (int)e.HitTestResult.Index; + model.InvalidatePlot(false); + }; + + return model; + } + + [Example("LineSeries and PlotModel MouseDown event")] + public static PlotModel MouseDownEvent() + { + var model = new PlotModel { Title = "MouseDown", Subtitle = "Left click to edit or add points." }; + var l = new Legend + { + LegendSymbolLength = 40 + }; + + model.Legends.Add(l); + + // Add a line series + var s1 = new LineSeries + { + Title = "LineSeries1", + Color = OxyColors.SkyBlue, + MarkerType = MarkerType.Circle, + MarkerSize = 6, + MarkerStroke = OxyColors.White, + MarkerFill = OxyColors.SkyBlue, + MarkerStrokeThickness = 1.5 + }; + s1.Points.Add(new DataPoint(0, 10)); + s1.Points.Add(new DataPoint(10, 40)); + s1.Points.Add(new DataPoint(40, 20)); + s1.Points.Add(new DataPoint(60, 30)); + model.Series.Add(s1); + + int indexOfPointToMove = -1; + + // Subscribe to the mouse down event on the line series + s1.MouseDown += (s, e) => + { + // only handle the left mouse button (right button can still be used to pan) + if (e.ChangedButton == OxyMouseButton.Left) + { + int indexOfNearestPoint = (int)Math.Round(e.HitTestResult.Index); + var nearestPoint = s1.Transform(s1.Points[indexOfNearestPoint]); + + // Check if we are near a point + if ((nearestPoint - e.Position).Length < 10) + { + // Start editing this point + indexOfPointToMove = indexOfNearestPoint; + } + else + { + // otherwise create a point on the current line segment + int i = (int)e.HitTestResult.Index + 1; + s1.Points.Insert(i, s1.InverseTransform(e.Position)); + indexOfPointToMove = i; + } + + // Change the linestyle while editing + s1.LineStyle = LineStyle.DashDot; + + // Remember to refresh/invalidate of the plot + model.InvalidatePlot(false); + + // Set the event arguments to handled - no other handlers will be called. + e.Handled = true; + } + }; + + s1.MouseMove += (s, e) => + { + if (indexOfPointToMove >= 0) + { + // Move the point being edited. + s1.Points[indexOfPointToMove] = s1.InverseTransform(e.Position); + model.InvalidatePlot(false); + e.Handled = true; + } + }; + + s1.MouseUp += (s, e) => + { + // Stop editing + indexOfPointToMove = -1; + s1.LineStyle = LineStyle.Solid; + model.InvalidatePlot(false); + e.Handled = true; + }; + + model.MouseDown += (s, e) => + { + if (e.ChangedButton == OxyMouseButton.Left) + { + // Add a point to the line series. + s1.Points.Add(s1.InverseTransform(e.Position)); + indexOfPointToMove = s1.Points.Count - 1; + + model.InvalidatePlot(false); + e.Handled = true; + } + }; + return model; + } + + [Example("Add arrow annotations")] + public static PlotModel AddAnnotations() + { + var model = new PlotModel { Title = "Add arrow annotations", Subtitle = "Press and drag the left mouse button" }; + var xaxis = new LinearAxis { Position = AxisPosition.Bottom }; + var yaxis = new LinearAxis { Position = AxisPosition.Left }; + model.Axes.Add(xaxis); + model.Axes.Add(yaxis); + model.Series.Add(new FunctionSeries(x => Math.Sin(x / 4) * Math.Acos(Math.Sin(x)), 0, Math.PI * 8, 2000, "sin(x/4)*acos(sin(x))")); + + ArrowAnnotation tmp = null; + + // Add handlers to the PlotModel's mouse events + model.MouseDown += (s, e) => + { + if (e.ChangedButton == OxyMouseButton.Left) + { + // Create a new arrow annotation + tmp = new ArrowAnnotation(); + tmp.StartPoint = tmp.EndPoint = xaxis.InverseTransform(e.Position.X, e.Position.Y, yaxis); + model.Annotations.Add(tmp); + e.Handled = true; + } + }; + + // Handle mouse movements (note: this is only called when the mousedown event was handled) + model.MouseMove += (s, e) => + { + if (tmp != null) + { + // Modify the end point + tmp.EndPoint = xaxis.InverseTransform(e.Position.X, e.Position.Y, yaxis); + tmp.Text = string.Format("Y = {0:0.###}", tmp.EndPoint.Y); + + // Redraw the plot + model.InvalidatePlot(false); + e.Handled = true; + } + }; + + model.MouseUp += (s, e) => + { + if (tmp != null) + { + tmp = null; + e.Handled = true; + } + }; + + return model; + } + + [Example("LineAnnotation")] + public static PlotModel LineAnnotation() + { + var model = new PlotModel { Title = "LineAnnotation", Subtitle = "Click and drag the annotation line." }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 80 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + var la = new LineAnnotation { Type = LineAnnotationType.Vertical, X = 4 }; + la.MouseDown += (s, e) => + { + if (e.ChangedButton != OxyMouseButton.Left) + { + return; + } + + la.StrokeThickness *= 5; + model.InvalidatePlot(false); + e.Handled = true; + }; + + // Handle mouse movements (note: this is only called when the mousedown event was handled) + la.MouseMove += (s, e) => + { + la.X = la.InverseTransform(e.Position).X; + model.InvalidatePlot(false); + e.Handled = true; + }; + la.MouseUp += (s, e) => + { + la.StrokeThickness /= 5; + model.InvalidatePlot(false); + e.Handled = true; + }; + model.Annotations.Add(la); + return model; + } + + [Example("ArrowAnnotation")] + public static PlotModel ArrowAnnotation() + { + var model = new PlotModel { Title = "ArrowAnnotation", Subtitle = "Click and drag the arrow." }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -40, Maximum = 60 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + + var arrow = new ArrowAnnotation { StartPoint = new DataPoint(8, 4), EndPoint = new DataPoint(0, 0), Text = "Move me!" }; + + var lastPoint = DataPoint.Undefined; + bool moveStartPoint = false; + bool moveEndPoint = false; + var originalColor = OxyColors.White; + + // Handle left mouse clicks + arrow.MouseDown += (s, e) => + { + if (e.ChangedButton != OxyMouseButton.Left) + { + return; + } + + lastPoint = arrow.InverseTransform(e.Position); + moveStartPoint = e.HitTestResult.Index != 2; + moveEndPoint = e.HitTestResult.Index != 1; + originalColor = arrow.Color; + arrow.Color = OxyColors.Red; + model.InvalidatePlot(false); + e.Handled = true; + }; + + // Handle mouse movements (note: this is only called when the mousedown event was handled) + arrow.MouseMove += (s, e) => + { + var thisPoint = arrow.InverseTransform(e.Position); + double dx = thisPoint.X - lastPoint.X; + double dy = thisPoint.Y - lastPoint.Y; + if (moveStartPoint) + { + arrow.StartPoint = new DataPoint(arrow.StartPoint.X + dx, arrow.StartPoint.Y + dy); + } + + if (moveEndPoint) + { + arrow.EndPoint = new DataPoint(arrow.EndPoint.X + dx, arrow.EndPoint.Y + dy); + } + + lastPoint = thisPoint; + model.InvalidatePlot(false); + e.Handled = true; + }; + + // Handle mouse up (note: this is only called when the mousedown event was handled) + arrow.MouseUp += (s, e) => + { + arrow.Color = originalColor; + }; + model.Annotations.Add(arrow); + return model; + } + + [Example("PolygonAnnotation")] + public static PlotModel PolygonAnnotation() + { + var model = new PlotModel { Title = "PolygonAnnotation", Subtitle = "Click the polygon" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -20, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 20 }); + var pa = new PolygonAnnotation + { + Text = "Polygon 1" + }; + pa.Points.AddRange(new[] + { + new DataPoint(4, -2), new DataPoint(8, -4), new DataPoint(17, 7), new DataPoint(5, 8), + new DataPoint(2, 5) + }); + + // Handle left mouse clicks + int hitCount = 1; + pa.MouseDown += (s, e) => + { + if (e.ChangedButton != OxyMouseButton.Left) + { + return; + } + + pa.Text = "Hit # " + hitCount++; + model.InvalidatePlot(false); + e.Handled = true; + }; + + model.Annotations.Add(pa); + return model; + } + + [Example("TextAnnotation")] + public static PlotModel TextAnnotation() + { + var model = new PlotModel { Title = "TextAnnotation", Subtitle = "Click the text" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + var ta = new TextAnnotation + { + TextPosition = new DataPoint(4, -2), + Text = "Click here" + }; + + // Handle left mouse clicks + ta.MouseDown += (s, e) => + { + if (e.ChangedButton != OxyMouseButton.Left) + { + return; + } + + ta.Background = ta.Background.IsUndefined() ? OxyColors.LightGreen : OxyColors.Undefined; + model.InvalidatePlot(false); + e.Handled = true; + }; + + model.Annotations.Add(ta); + return model; + } + + [Example("ImageAnnotation")] + public static PlotModel ImageAnnotation() + { + var model = new PlotModel { Title = "ImageAnnotation", Subtitle = "Click the image" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -20, Maximum = 20 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -10, Maximum = 10 }); + + OxyImage image; + var assembly = typeof(MouseEventExamples).GetTypeInfo().Assembly; + using (var stream = assembly.GetManifestResourceStream("ExampleLibrary.Resources.OxyPlot.png")) + { + image = new OxyImage(stream); + } + + var ia = new ImageAnnotation { ImageSource = image, X = new PlotLength(4, PlotLengthUnit.Data), Y = new PlotLength(2, PlotLengthUnit.Data), HorizontalAlignment = HorizontalAlignment.Right }; + model.Annotations.Add(ia); + + // Handle left mouse clicks + ia.MouseDown += (s, e) => + { + if (e.ChangedButton != OxyMouseButton.Left) + { + return; + } + + ia.HorizontalAlignment = ia.HorizontalAlignment == HorizontalAlignment.Right ? HorizontalAlignment.Left : HorizontalAlignment.Right; + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("Add Series")] + public static PlotModel AddSeriesByMouseDownEvent() + { + var model = new PlotModel { Title = "MouseDown", Subtitle = "Left click to add series." }; + var l = new Legend + { + LegendSymbolLength = 40 + }; + + model.Legends.Add(l); + + model.MouseDown += (s, e) => + { + if (e.ChangedButton == OxyMouseButton.Left) + { + double a = model.Series.Count + 1; + model.Series.Add(new FunctionSeries(x => Math.Sin(a * x), 0, 10, 1000)); + model.InvalidatePlot(true); + e.Handled = true; + } + }; + + return model; + } + + [Example("Select range")] + public static PlotModel SelectRange() + { + var model = new PlotModel { Title = "Select range", Subtitle = "Left click and drag to select a range." }; + model.Series.Add(new FunctionSeries(Math.Cos, 0, 40, 0.1)); + + var range = new RectangleAnnotation { Fill = OxyColor.FromAColor(120, OxyColors.SkyBlue), MinimumX = 0, MaximumX = 0 }; + model.Annotations.Add(range); + + double startx = double.NaN; + + model.MouseDown += (s, e) => + { + if (e.ChangedButton == OxyMouseButton.Left) + { + startx = range.InverseTransform(e.Position).X; + range.MinimumX = startx; + range.MaximumX = startx; + model.InvalidatePlot(true); + e.Handled = true; + } + }; + model.MouseMove += (s, e) => + { + if (!double.IsNaN(startx)) + { + var x = range.InverseTransform(e.Position).X; + range.MinimumX = Math.Min(x, startx); + range.MaximumX = Math.Max(x, startx); + range.Text = string.Format("∫ cos(x) dx = {0:0.00}", Math.Sin(range.MaximumX) - Math.Sin(range.MinimumX)); + model.Subtitle = string.Format("Integrating from {0:0.00} to {1:0.00}", range.MinimumX, range.MaximumX); + model.InvalidatePlot(true); + e.Handled = true; + } + }; + + model.MouseUp += (s, e) => + { + startx = double.NaN; + }; + + return model; + } + + [Example("Hover")] + public static PlotModel Hover() + { + var model = new PlotModel { Title = "Hover" }; + LineSeries series = null; + + model.MouseEnter += (s, e) => + { + model.Subtitle = "The mouse entered"; + series = new LineSeries(); + model.Series.Add(series); + model.InvalidatePlot(false); + e.Handled = true; + }; + + model.MouseMove += (s, e) => + { + if (series != null && series.XAxis != null) + { + series.Points.Add(series.InverseTransform(e.Position)); + model.InvalidatePlot(false); + } + }; + + model.MouseLeave += (s, e) => + { + model.Subtitle = "The mouse left"; + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("Touch")] + public static PlotModel Touch() + { + var model = new PlotModel { Title = "Touch" }; + var series = new LineSeries(); + model.Series.Add(series); + + model.TouchStarted += (s, e) => + { + model.Subtitle = "The touch gesture started"; + model.InvalidatePlot(false); + e.Handled = true; + }; + + model.TouchDelta += (s, e) => + { + series.Points.Add(series.InverseTransform(e.Position)); + model.InvalidatePlot(false); + }; + + model.TouchCompleted += (s, e) => + { + model.Subtitle = "The touch gesture completed"; + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("Touch on a LineSeries")] + public static PlotModel TouchSeries() + { + var model = new PlotModel { Title = "Touch on a LineSeries" }; + var series = new LineSeries(); + series.Points.Add(new DataPoint(0, 0)); + series.Points.Add(new DataPoint(10, 10)); + model.Series.Add(series); + + series.TouchStarted += (s, e) => + { + model.Subtitle = "The touch gesture started on the LineSeries"; + model.InvalidatePlot(false); + e.Handled = true; + }; + + series.TouchDelta += (s, e) => + { + series.Points.Add(series.InverseTransform(e.Position)); + model.InvalidatePlot(false); + }; + + series.TouchCompleted += (s, e) => + { + model.Subtitle = "The touch gesture completed"; + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("RectangleAnnotation click")] + public static PlotModel RectangleAnnotationClick() + { + var plotModel = new PlotModel { Title = "RectangleAnnotation click" }; + + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var annotation = new RectangleAnnotation() { MinimumX = 10, MaximumX = 60, MinimumY = 10, MaximumY = 20 }; + plotModel.Annotations.Add(annotation); + + int i = 0; + annotation.MouseDown += (s, e) => + { + annotation.Text = "Clicked " + (++i) + " times."; + plotModel.InvalidatePlot(false); + }; + + return plotModel; + } + + [Example("Clicking on an annotation")] + public static PlotModel ClickingOnAnAnnotation() + { + var plotModel = new PlotModel { Title = "Clicking on an annotation", Subtitle = "Click on the rectangles" }; + + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var annotation1 = new RectangleAnnotation { Fill = OxyColors.Green, Text = "RectangleAnnotation 1", MinimumX = 25, MaximumX = 75, MinimumY = 20, MaximumY = 40 }; + plotModel.Annotations.Add(annotation1); + + var annotation2 = new RectangleAnnotation { Fill = OxyColors.SkyBlue, Text = "RectangleAnnotation 2", MinimumX = 25, MaximumX = 75, MinimumY = 60, MaximumY = 80 }; + plotModel.Annotations.Add(annotation2); + + EventHandler handleMouseClick = (s, e) => + { + plotModel.Subtitle = "You clicked " + ((RectangleAnnotation)s).Text; + plotModel.InvalidatePlot(false); + }; + + annotation1.MouseDown += handleMouseClick; + annotation2.MouseDown += handleMouseClick; + + return plotModel; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/PerformanceExamples.cs b/Source/Examples/ExampleLibrary/Examples/PerformanceExamples.cs new file mode 100644 index 0000000..ea93d84 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/PerformanceExamples.cs @@ -0,0 +1,354 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("Performance")] + public class PerformanceExamples + { + [Example("LineSeries, 1M points")] + public static PlotModel LineSeries1M() + { + var model = new PlotModel { Title = "LineSeries, 1M points" }; + var s1 = new LineSeries(); + AddPoints(s1.Points, 1000000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 1M points, EdgeRenderingMode==PreferSpeed")] + public static PlotModel LineSeries1MSpeed() + { + var model = new PlotModel { Title = "LineSeries, 1M points" }; + var s1 = new LineSeries() { EdgeRenderingMode = EdgeRenderingMode.PreferSpeed }; + AddPoints(s1.Points, 1000000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 100k points")] + public static PlotModel LineSeries() + { + var model = new PlotModel { Title = "LineSeries, 100k points" }; + var s1 = new LineSeries(); + AddPoints(s1.Points, 100000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 100k points (dashed line)")] + public static PlotModel LineSeriesDashedLines() + { + var model = new PlotModel { Title = "LineSeries, 100k points", Subtitle = "LineStyle = Dash" }; + var s1 = new LineSeries { LineStyle = LineStyle.Dash }; + AddPoints(s1.Points, 100000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 100k points, markers")] + public static PlotModel LineSeries1WithMarkers() + { + var model = new PlotModel { Title = "LineSeries, 100k points", Subtitle = "MarkerType = Square" }; + var s1 = new LineSeries { MarkerType = MarkerType.Square }; + AddPoints(s1.Points, 100000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 100k points, markers, lower resolution")] + public static PlotModel LineSeries1WithMarkersLowRes() + { + var model = new PlotModel { Title = "LineSeries, 100k points, markers, lower resolution", Subtitle = "MarkerType = Square, MarkerResolution = 3" }; + var s1 = new LineSeries { MarkerType = MarkerType.Square, MarkerResolution = 3 }; + AddPoints(s1.Points, 100000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 100k points, round line joins")] + public static PlotModel LineSeriesRoundLineJoins() + { + var model = new PlotModel { Title = "LineSeries, 100k points", Subtitle = "LineJoin = Round" }; + var s1 = new LineSeries { LineJoin = LineJoin.Round }; + AddPoints(s1.Points, 100000); + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 100k points by ItemsSource set to a List")] + public static PlotModel LineSeriesItemsSourceList() + { + var model = new PlotModel { Title = "LineSeries, 100k points by ItemsSource set to a List" }; + var s1 = new LineSeries(); + var points = new List(); + AddPoints(points, 100000); + s1.ItemsSource = points; + model.Series.Add(s1); + + return model; + } + + [Example("LineSeries, 100k points by ItemsSource and Mapping")] + public static PlotModel LineSeriesItemsSourceMapping() + { + var model = new PlotModel { Title = "LineSeries, 100k points by ItemsSource and Mapping", Subtitle = "Using the Mapping function" }; + var s1 = new LineSeries(); + var points = new List(); + AddPoints(points, 100000); + var rects = points.Select(pt => new OxyRect(pt.X, pt.Y, 0, 0)).ToList(); + s1.ItemsSource = rects; + s1.Mapping = r => new DataPoint(((OxyRect)r).Left, ((OxyRect)r).Top); + model.Series.Add(s1); + + return model; + } + + [Example("LineSeries, 100k points by ItemsSource and reflection")] + public static PlotModel LineSeriesItemsSourceReflection() + { + var model = new PlotModel { Title = "LineSeries, 100k points, ItemsSource with reflection", Subtitle = "DataFieldX and DataFieldY" }; + var s1 = new LineSeries(); + var points = new List(); + AddPoints(points, 100000); + var rects = points.Select(pt => new OxyRect(pt.X, pt.Y, 0, 0)).ToList(); + s1.ItemsSource = rects; + s1.DataFieldX = "Left"; + s1.DataFieldY = "Top"; + model.Series.Add(s1); + + return model; + } + + [Example("LineSeries, 100k points (thick)")] + public static PlotModel LineSeriesThick() + { + var model = new PlotModel { Title = "LineSeries, 100k points (thick)", Subtitle = "StrokeThickness = 10" }; + var s1 = new LineSeries { StrokeThickness = 10 }; + AddPoints(s1.Points, 100000); + model.Series.Add(s1); + + return model; + } + + [Example("LineSeries, 3k points, miter line joins")] + public static PlotModel LineSeries2MiterLineJoins() + { + var model = new PlotModel { Title = "LineSeries, 3k points, miter line joins", Subtitle = "LineJoin = Miter" }; + var s1 = new LineSeries { LineJoin = LineJoin.Miter, StrokeThickness = 8.0 }; + for (int i = 0; i < 3000; i++) + { + s1.Points.Add(new DataPoint(i, i % 2)); + } + + model.Series.Add(s1); + + return model; + } + + [Example("LineSeries, 3k points, round line joins")] + public static PlotModel LineSeries2RoundLineJoins() + { + var model = new PlotModel { Title = "LineSeries, 3k points, round line joins", Subtitle = "LineJoin = Round" }; + var s1 = new LineSeries { LineJoin = LineJoin.Round, StrokeThickness = 8.0 }; + for (int i = 0; i < 3000; i++) + { + s1.Points.Add(new DataPoint(i, i % 2)); + } + + model.Series.Add(s1); + return model; + } + + [Example("LineSeries, 3k points, bevel line joins")] + public static PlotModel LineSeries2BevelLineJoins() + { + var model = new PlotModel { Title = "LineSeries, 3k points, bevel line joins", Subtitle = "LineJoin = Bevel" }; + var s1 = new LineSeries { LineJoin = LineJoin.Bevel, StrokeThickness = 8.0 }; + for (int i = 0; i < 3000; i++) + { + s1.Points.Add(new DataPoint(i, i % 2)); + } + + model.Series.Add(s1); + return model; + } + + [Example("ScatterSeries (squares)")] + public static PlotModel ScatterSeriesSquares() + { + var model = new PlotModel { Title = "ScatterSeries (squares)" }; + var s1 = new ScatterSeries(); + AddPoints(s1.Points, 2000); + model.Series.Add(s1); + return model; + } + + [Example("ScatterSeries (squares with outline)")] + public static PlotModel ScatterSeriesSquaresOutline() + { + var model = new PlotModel { Title = "ScatterSeries (squares with outline)", Subtitle = "MarkerStroke = Black" }; + var s1 = new ScatterSeries { MarkerStroke = OxyColors.Black }; + AddPoints(s1.Points, 2000); + model.Series.Add(s1); + return model; + } + + [Example("ScatterSeries (squares without fill color)")] + public static PlotModel ScatterSeriesSquaresOutlineOnly() + { + var model = new PlotModel { Title = "ScatterSeries (squares without fill color)", Subtitle = ";arkerFill = Transparent, MarkerStroke = Black" }; + var s1 = new ScatterSeries { MarkerFill = OxyColors.Transparent, MarkerStroke = OxyColors.Black }; + AddPoints(s1.Points, 2000); + model.Series.Add(s1); + return model; + } + + [Example("ScatterSeries by ItemsSource and reflection")] + public static PlotModel ScatterSeriesItemsSourceReflection() + { + var model = new PlotModel { Title = "ScatterSeries (by ItemsSource)", Subtitle = "DataFieldX = 'X', DataFieldY = 'Y'" }; + model.Series.Add(new ScatterSeries { ItemsSource = GetPoints(2000), DataFieldX = "X", DataFieldY = "Y" }); + return model; + } + + [Example("ScatterSeries (circles)")] + public static PlotModel ScatterSeriesCircles() + { + var model = new PlotModel { Title = "ScatterSeries (circles)", Subtitle = "MarkerType = Circle" }; + var s1 = new ScatterSeries { MarkerType = MarkerType.Circle }; + AddPoints(s1.Points, 2000); + model.Series.Add(s1); + return model; + } + + [Example("ScatterSeries (circles with outline)")] + public static PlotModel ScatterSeriesCirclesOutline() + { + var model = new PlotModel { Title = "ScatterSeries (circles with outline)", Subtitle = "MarkerType = Circle, MarkerStroke = Black" }; + var s1 = new ScatterSeries { MarkerType = MarkerType.Circle, MarkerStroke = OxyColors.Black }; + AddPoints(s1.Points, 2000); + model.Series.Add(s1); + return model; + } + + [Example("ScatterSeries (cross)")] + public static PlotModel ScatterSeriesCrosses() + { + var model = new PlotModel { Title = "ScatterSeries (cross)", Subtitle = "MarkerType = Cross" }; + var s1 = new ScatterSeries + { + MarkerType = MarkerType.Cross, + MarkerFill = OxyColors.Undefined, + MarkerStroke = OxyColors.Black + }; + AddPoints(s1.Points, 2000); + model.Series.Add(s1); + return model; + } + + [Example("LinearAxis (no gridlines)")] + public static PlotModel LinearAxisNoGridlines() + { + var model = new PlotModel { Title = "LinearAxis (no gridlines)" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1 }); + return model; + } + + [Example("LinearAxis (solid gridlines)")] + public static PlotModel LinearAxisSolidGridlines() + { + var model = new PlotModel { Title = "LinearAxis (solid gridlines)" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1, MajorGridlineStyle = LineStyle.Solid }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1, MajorGridlineStyle = LineStyle.Solid }); + return model; + } + + [Example("LinearAxis (dashed gridlines)")] + public static PlotModel LinearAxisDashedGridlines() + { + var model = new PlotModel { Title = "LinearAxis (dashed gridlines)" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1, MajorGridlineStyle = LineStyle.Dash }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1, MajorGridlineStyle = LineStyle.Dash }); + return model; + } + + [Example("LinearAxis (dotted gridlines)")] + public static PlotModel LinearAxisDottedGridlines() + { + var model = new PlotModel { Title = "LinearAxis (dotted gridlines)" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1, MajorGridlineStyle = LineStyle.Dot }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100, MajorStep = 1, MinorStep = 1, MajorGridlineStyle = LineStyle.Dot }); + return model; + } + + [Example("int overflow (10k)")] + public static PlotModel IntOverflow10k() + { + return IntOverflow(10000); + } + + [Example("int overflow (50k)")] + public static PlotModel IntOverflow50k() + { + return IntOverflow(50000); + } + + [Example("int overflow (100k)")] + public static PlotModel IntOverflow100k() + { + return IntOverflow(100000); + } + + private static PlotModel IntOverflow(int n) + { + var model = new PlotModel { Title = "int overflow", Subtitle = "n = " + n }; + var ls = new LineSeries(); + int k = 0; + for (int i = 0; i < n; i++) + { + ls.Points.Add(new DataPoint(i, k += i * i)); + } + + model.Series.Add(ls); + return model; + } + + private static List GetPoints(int n) + { + var points = new List(); + AddPoints(points, n); + return points; + } + + private static void AddPoints(ICollection points, int n) + { + for (int i = 0; i < n; i++) + { + double x = Math.PI * 10 * i / (n - 1); + points.Add(new DataPoint(x * Math.Cos(x), x * Math.Sin(x))); + } + } + + private static void AddPoints(ICollection points, int n) + { + for (int i = 0; i < n; i++) + { + double x = Math.PI * 10 * i / (n - 1); + points.Add(new ScatterPoint(x * Math.Cos(x), x * Math.Sin(x))); + } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/PlotControllerExamples.cs b/Source/Examples/ExampleLibrary/Examples/PlotControllerExamples.cs new file mode 100644 index 0000000..e982988 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/PlotControllerExamples.cs @@ -0,0 +1,208 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Linq; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("PlotController examples")] + public static class PlotControllerExamples + { + [Example("Basic controller example")] + public static Example BasicExample() + { + var model = new PlotModel { Title = "Basic Controller example", Subtitle = "Panning with left mouse button" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); + return new Example(model, controller); + } + + [Example("Show tracker without clicking")] + public static Example HoverTracking() + { + var model = new PlotModel { Title = "Show tracker without clicking" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Series.Add(new FunctionSeries(t => (Math.Cos(t) * 5) + Math.Cos(t * 50), t => (Math.Sin(t) * 5) + Math.Sin(t * 50), 0, Math.PI * 2, 20000)); + + // create a new plot controller with default bindings + var controller = new PlotController(); + + // add a tracker command to the mouse enter event + controller.BindMouseEnter(PlotCommands.HoverPointsOnlyTrack); + + return new Example(model, controller); + } + + [Example("Mouse handling example")] + public static Example MouseHandlingExample() + { + var model = new PlotModel { Title = "Mouse handling example" }; + var series = new ScatterSeries(); + model.Series.Add(series); + + // Create a command that adds points to the scatter series + var command = new DelegatePlotCommand( + (v, c, a) => + { + a.Handled = true; + var point = series.InverseTransform(a.Position); + series.Points.Add(new ScatterPoint(point.X, point.Y)); + model.InvalidatePlot(true); + }); + + var controller = new PlotController(); + controller.BindMouseDown(OxyMouseButton.Left, command); + + return new Example(model, controller); + } + + [Example("Clicking on an annotation")] + public static Example ClickingOnAnAnnotation() + { + var plotModel = new PlotModel { Title = "Clicking on an annotation", Subtitle = "Click on the rectangles" }; + + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var annotation1 = new RectangleAnnotation { Fill = OxyColors.Green, Text = "RectangleAnnotation 1", MinimumX = 25, MaximumX = 75, MinimumY = 20, MaximumY = 40 }; + plotModel.Annotations.Add(annotation1); + + var annotation2 = new RectangleAnnotation { Fill = OxyColors.SkyBlue, Text = "RectangleAnnotation 2", MinimumX = 25, MaximumX = 75, MinimumY = 60, MaximumY = 80 }; + plotModel.Annotations.Add(annotation2); + + EventHandler handleMouseClick = (s, e) => + { + plotModel.Subtitle = "You clicked " + ((RectangleAnnotation)s).Text; + plotModel.InvalidatePlot(false); + }; + + annotation1.MouseDown += handleMouseClick; + annotation2.MouseDown += handleMouseClick; + + var controller = new PlotController(); + var handleClick = new DelegatePlotCommand( + (v, c, e) => + { + var args = new HitTestArguments(e.Position, 10); + var firstHit = v.ActualModel.HitTest(args).FirstOrDefault(x => x.Element is RectangleAnnotation); + if (firstHit != null) + { + e.Handled = true; + plotModel.Subtitle = "You clicked " + ((RectangleAnnotation)firstHit.Element).Text; + plotModel.InvalidatePlot(false); + } + }); + controller.Bind(new OxyMouseDownGesture(OxyMouseButton.Left), handleClick); + + return new Example(plotModel, controller); + } + + [Example("Preferring an axis for manipulation")] + public static Example PreferringAnAxisForManipulation() + { + var model = new PlotModel + { + Title = "Preferring an axis for manipulation", + Subtitle = "Mouse wheel over plot area prefers X axis", + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + model.Series.Add(new FunctionSeries(Math.Cos, -7, 7, 0.01)); + + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseWheel(new DelegatePlotCommand((view, _, args) => HandleZoomByWheel(view, args))); + controller.BindMouseWheel(OxyModifierKeys.Control, new DelegatePlotCommand((view, _, args) => HandleZoomByWheel(view, args, 0.1))); + + return new Example(model, controller); + + void HandleZoomByWheel(IPlotView view, OxyMouseWheelEventArgs args, double factor = 1) + { + var m = new ZoomStepManipulator(view) + { + AxisPreference = AxisPreference.X, + Step = args.Delta * 0.001 * factor, + FineControl = args.IsControlDown, + }; + m.Started(args); + } + } + + [Example("Show/Hide Legend")] + public static Example ShowHideLegend() + { + var plotModel = new PlotModel { Title = "Show/Hide Legend", Subtitle = "Click on the rectangles" }; + + int n = 3; + for (int i = 1; i <= n; i++) + { + var s = new LineSeries { Title = "Series " + i }; + plotModel.Series.Add(s); + for (double x = 0; x < 2 * Math.PI; x += 0.1) + { + s.Points.Add(new DataPoint(x, (Math.Sin(x * i) / i) + i)); + } + } + var l = new Legend(); + + plotModel.Legends.Add(l); + + var annotation1 = new RectangleAnnotation { Fill = OxyColors.Green, Text = "Show Legend", MinimumX = 0.5, MaximumX = 1.5, MinimumY = .2, MaximumY = 0.4 }; + plotModel.Annotations.Add(annotation1); + + var annotation2 = new RectangleAnnotation { Fill = OxyColors.SkyBlue, Text = "Hide Legend", MinimumX = 0.5, MaximumX = 1.5, MinimumY = 0.6, MaximumY = 0.8 }; + plotModel.Annotations.Add(annotation2); + + EventHandler handleMouseClick = (s, e) => + { + string annotationText = ((RectangleAnnotation)s).Text; + if (annotationText == "Show Legend") + { + plotModel.IsLegendVisible = true; + } + else if (annotationText == "Hide Legend") + { + plotModel.IsLegendVisible = false; + } + + plotModel.Subtitle = "You clicked " + ((RectangleAnnotation)s).Text; + plotModel.InvalidatePlot(false); + }; + + annotation1.MouseDown += handleMouseClick; + annotation2.MouseDown += handleMouseClick; + + var controller = new PlotController(); + var handleClick = new DelegatePlotCommand( + (v, c, e) => + { + var args = new HitTestArguments(e.Position, 10); + var firstHit = v.ActualModel.HitTest(args).FirstOrDefault(x => x.Element is RectangleAnnotation); + if (firstHit != null) + { + e.Handled = true; + plotModel.Subtitle = "You clicked " + ((RectangleAnnotation)firstHit.Element).Text; + plotModel.InvalidatePlot(false); + } + }); + controller.Bind(new OxyMouseDownGesture(OxyMouseButton.Left), handleClick); + + return new Example(plotModel, controller); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/PlotModelExamples.cs b/Source/Examples/ExampleLibrary/Examples/PlotModelExamples.cs new file mode 100644 index 0000000..279a013 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/PlotModelExamples.cs @@ -0,0 +1,243 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using System; + + [Examples("PlotModel examples")] + public static class PlotModelExamples + { + [Example("Title")] + public static PlotModel Title() + { + var model = new PlotModel { Title = "Title" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Title and Subtitle")] + public static PlotModel TitleAndSubtitle() + { + var model = new PlotModel { Title = "Title", Subtitle = "Subtitle" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Sub- and superscript in titles")] + public static PlotModel TitleAndSubtitleWithSubSuperscript() + { + var model = new PlotModel { Title = "Title with^{super}_{sub}script", Subtitle = "Subtitle with^{super}_{sub}script" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("TitlePadding = 0")] + public static PlotModel TitlePadding0() + { + var model = new PlotModel { Title = "TitlePadding = 0", Subtitle = "This controls the distance between the titles and the plot area. The default value is 6", TitlePadding = 0 }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("TitlePadding = 100")] + public static PlotModel TitlePadding100() + { + var model = new PlotModel { Title = "TitlePadding = 100", TitlePadding = 100 }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("TitleHorizontalAlignment = CenteredWithinView")] + public static PlotModel TitlesCenteredWithinView() + { + var model = new PlotModel { Title = "Title", Subtitle = "Subtitle", TitleHorizontalAlignment = TitleHorizontalAlignment.CenteredWithinView }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("TitleClippingOff")] + public static PlotModel TitleClippingOff() + { + var model = new PlotModel { Title = "This is a very long title to illustrate that title clipping is necessary, because currently it's not clipped.", ClipTitle = false }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("TitleClipping60")] + public static PlotModel TitleClipping60() + { + var model = new PlotModel { Title = "This is a very long title, that shows that title clippling is working with crrently 60% of title area", TitleClippingLength = 0.6}; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("No model")] + public static PlotModel NoModel() + { + return null; + } + + [Example("Background = Undefined (default)")] + public static PlotModel BackgroundUndefined() + { + var model = new PlotModel { Title = "Background = Undefined", Background = OxyColors.Undefined }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Background = 50% White")] + public static PlotModel BackgroundWhite50() + { + var model = new PlotModel { Title = "Background = 50% White", Background = OxyColor.FromAColor(128, OxyColors.White) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Background = Transparent")] + public static PlotModel BackgroundTransparent() + { + var model = new PlotModel { Title = "Background = Transparent", Background = OxyColors.Transparent }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Background = LightSkyBlue")] + public static PlotModel BackgroundLightGray() + { + var model = new PlotModel { Title = "Background = LightSkyBlue", Background = OxyColors.LightSkyBlue }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Background = White")] + public static PlotModel BackgroundWhite() + { + var model = new PlotModel { Title = "Background = White", Background = OxyColors.White }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("Background = Black")] + public static PlotModel BackgroundBlack() + { + var model = new PlotModel { Title = "Background = Black", Background = OxyColors.Black, TextColor = OxyColors.White, TitleColor = OxyColors.White, PlotAreaBorderColor = OxyColors.White }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, TicklineColor = OxyColors.White }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, TicklineColor = OxyColors.White }); + return model; + } + + [Example("PlotAreaBorderThickness = 2")] + public static PlotModel PlotAreaBorderThickness2() + { + var model = new PlotModel { Title = "PlotAreaBorderThickness = 2", PlotAreaBorderThickness = new OxyThickness(2) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("PlotAreaBorderThickness = (1,0,0,1)")] + public static PlotModel PlotAreaBorderThickness1001() + { + var model = new PlotModel { Title = "PlotAreaBorderThickness = (1,0,0,1)", PlotAreaBorderThickness = new OxyThickness(1, 0, 0, 1) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("PlotAreaBorderThickness = (4,1,1,4)")] + public static PlotModel PlotAreaBorderThickness4114() + { + var model = new PlotModel { Title = "PlotAreaBorderThickness = (4,1,1,4)", PlotAreaBorderThickness = new OxyThickness(4, 1, 1, 4) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("PlotAreaBorderThickness = 0")] + public static PlotModel PlotAreaBorderThickness0() + { + var model = new PlotModel { Title = "PlotAreaBorderThickness = 0", PlotAreaBorderThickness = new OxyThickness(0) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + [Example("PlotAreaBorderThickness / AxisLine")] + public static PlotModel PlotAreaBorderThickness0AxisLineThickness1() + { + var model = new PlotModel { Title = "PlotAreaBorderThickness = 0", Subtitle = "AxislineThickness = 1, AxislineColor = OxyColors.Blue, AxislineStyle = LineStyle.Solid", PlotAreaBorderThickness = new OxyThickness(0) }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, AxislineThickness = 1, AxislineColor = OxyColors.Blue, AxislineStyle = LineStyle.Solid }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, AxislineThickness = 1, AxislineColor = OxyColors.Blue, AxislineStyle = LineStyle.Solid }); + return model; + } + + [Example("Exception handling (invalid XAxisKey)")] + public static PlotModel InvalidAxisKey() + { + var model = new PlotModel(); + model.Axes.Add(new LinearAxis()); + model.Series.Add(new LineSeries { XAxisKey = "invalidKey" }); + return model; + } + + [Example("Exception handling (with clipping)")] + public static PlotModel ExceptionClipping() + { + var model = new PlotModel(); + var annotation = new RenderingCapabilities.DelegateAnnotation(rc => + { + rc.PushClip(new OxyRect(50, 50, 50, 50)); + throw new Exception("This Exception should be completely visible and not clipped by the previously pushed clipping rectangle."); + }); + + model.Annotations.Add(annotation); + return model; + } + + [Example("Unbalanced clipping (push)")] + public static PlotModel UnbalancedClippingPush() + { + var model = new PlotModel(); + var annotation = new RenderingCapabilities.DelegateAnnotation(rc => + { + rc.PushClip(new OxyRect(50, 50, 50, 50)); + }); + + model.Annotations.Add(annotation); + return model; + } + + [Example("Unbalanced clipping (pop)")] + public static PlotModel UnbalancedClippingPop() + { + var model = new PlotModel(); + var annotation = new RenderingCapabilities.DelegateAnnotation(rc => + { + rc.PopClip(); + }); + + model.Annotations.Add(annotation); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/RenderingCapabilities.cs b/Source/Examples/ExampleLibrary/Examples/RenderingCapabilities.cs new file mode 100644 index 0000000..1dcbe4b --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/RenderingCapabilities.cs @@ -0,0 +1,904 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides rendering capability examples. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Diagnostics; + using System.Globalization; + + using OxyPlot; + using OxyPlot.Annotations; + using System.Linq; + using System.Collections.Generic; + + /// + /// Provides rendering capability examples. + /// + [Examples("9 Rendering capabilities")] + public class RenderingCapabilities + { + /// + /// Shows color capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Colors")] + public static PlotModel DrawTextColors() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const string Font = "Arial"; + const double FontSize = 32d; + const double FontWeight = FontWeights.Bold; + const double D = FontSize * 1.6; + const double X = 20; + double y = 20 - D; + + + rc.DrawText(new ScreenPoint(X, y += D), "Black", OxyColors.Black, Font, FontSize, FontWeight); + rc.DrawText(new ScreenPoint(X, y += D), "Red", OxyColors.Red, Font, FontSize, FontWeight); + rc.DrawText(new ScreenPoint(X, y += D), "Green", OxyColors.Green, Font, FontSize, FontWeight); + rc.DrawText(new ScreenPoint(X, y += D), "Blue", OxyColors.Blue, Font, FontSize, FontWeight); + + rc.FillRectangle(new OxyRect(X, y + D + 15, 200, 10), OxyColors.Black, EdgeRenderingMode.Adaptive); + rc.DrawText(new ScreenPoint(X, y + D), "Yellow 50%", OxyColor.FromAColor(128, OxyColors.Yellow), Font, FontSize, FontWeight); + })); + return model; + } + + /// + /// Shows font capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Fonts")] + public static PlotModel DrawTextFonts() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const double FontSize = 20d; + const double D = FontSize * 1.6; + const double X = 20; + double y = 20 - D; + + rc.DrawText(new ScreenPoint(X, y += D), "Default font", OxyColors.Black, null, FontSize); + rc.DrawText(new ScreenPoint(X, y += D), "Helvetica", OxyColors.Black, "Helvetica", FontSize); + rc.DrawText(new ScreenPoint(X, y += D), "Arial", OxyColors.Black, "Arial", FontSize); + rc.DrawText(new ScreenPoint(X, y += D), "Courier", OxyColors.Black, "Courier", FontSize); + rc.DrawText(new ScreenPoint(X, y += D), "Courier New", OxyColors.Black, "Courier New", FontSize); + rc.DrawText(new ScreenPoint(X, y += D), "Times", OxyColors.Black, "Times", FontSize); + rc.DrawText(new ScreenPoint(X, y + D), "Times New Roman", OxyColors.Black, "Times New Roman", FontSize); + })); + return model; + } + + /// + /// Shows font size capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Font sizes")] + public static PlotModel DrawTextFontSizes() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const double X = 20; + double y = 20; + + // Font sizes + foreach (var size in new[] { 10, 16, 24, 36, 48 }) + { + rc.DrawText(new ScreenPoint(X, y), size + "pt", OxyColors.Black, "Arial", size); + rc.DrawText(new ScreenPoint(X + 200, y), size + "pt", OxyColors.Black, "Arial", size, FontWeights.Bold); + y += size * 1.6; + } + })); + return model; + } + + /// + /// Shows rotation capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Rotation")] + public static PlotModel DrawTextRotation() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + var origin = new ScreenPoint(200, 200); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + for (int rotation = 0; rotation < 360; rotation += 45) + { + rc.DrawText(origin, string.Format("Rotation {0}", rotation), OxyColors.Black, fontSize: 20d, rotation: rotation); + } + })); + return model; + } + + /// + /// Shows alignment capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Alignment")] + public static PlotModel DrawTextAlignment() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const double FontSize = 20d; + + for (var ha = HorizontalAlignment.Left; ha <= HorizontalAlignment.Right; ha++) + { + for (var va = VerticalAlignment.Top; va <= VerticalAlignment.Bottom; va++) + { + var origin = new ScreenPoint((((int)ha + 1) * 200) + 20, (((int)va + 1) * FontSize * 3) + 20); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + rc.DrawText(origin, ha + "-" + va, OxyColors.Black, fontSize: FontSize, horizontalAlignment: ha, verticalAlignment: va); + } + } + })); + return model; + } + + /// + /// Shows alignment capabilities for the DrawText method with multi-line text. + /// + /// A plot model. + [Example("DrawText - Multi-line Alignment")] + public static PlotModel DrawTextMultiLineAlignment() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const double FontSize = 20d; + + for (var ha = HorizontalAlignment.Left; ha <= HorizontalAlignment.Right; ha++) + { + for (var va = VerticalAlignment.Top; va <= VerticalAlignment.Bottom; va++) + { + var origin = new ScreenPoint((((int)ha + 1) * 200) + 20, (((int)va + 1) * FontSize * 6) + 20); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + rc.DrawText(origin, ha + "\r\n" + va, OxyColors.Black, fontSize: FontSize, horizontalAlignment: ha, verticalAlignment: va); + } + } + })); + return model; + } + + /// + /// Shows rotation capabilities for the DrawMathText method. + /// + /// A plot model. + [Example("DrawMathText - Rotation")] + public static PlotModel MathTextRotation() + { + var model = new PlotModel(); + var fontFamily = "Arial"; + var fontSize = 24; + var fontWeight = FontWeights.Normal; + model.Annotations.Add(new DelegateAnnotation(rc => + { + var origin = new ScreenPoint(200, 200); + var origin2 = new ScreenPoint(400, 200); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + for (int rotation = 0; rotation < 360; rotation += 45) + { + var text = " A_{2}^{3}B"; + rc.DrawMathText(origin, text, OxyColors.Black, fontFamily, fontSize, fontWeight, rotation, HorizontalAlignment.Left, VerticalAlignment.Middle); + var size = rc.MeasureMathText(text, fontFamily, fontSize, fontWeight); + var outline1 = size.GetPolygon(origin, rotation, HorizontalAlignment.Left, VerticalAlignment.Middle).ToArray(); + rc.DrawPolygon(outline1, OxyColors.Undefined, OxyColors.Blue, 1, EdgeRenderingMode.Adaptive); + + // Compare with normal text + var text2 = " A B"; + rc.DrawText(origin2, text2, OxyColors.Red, fontFamily, fontSize, fontWeight, rotation, HorizontalAlignment.Left, VerticalAlignment.Middle); + var size2 = rc.MeasureText(text2, fontFamily, fontSize, fontWeight); + var outline2 = size2.GetPolygon(origin2, rotation, HorizontalAlignment.Left, VerticalAlignment.Middle).ToArray(); + rc.DrawPolygon(outline2, OxyColors.Undefined, OxyColors.Blue, 1, EdgeRenderingMode.Adaptive); + } + })); + return model; + } + + /// + /// Shows alignment capabilities for the DrawMathText method. + /// + /// A plot model. + [Example("DrawMathText - Alignment")] + public static PlotModel DrawMathTextAlignment() + { + var text = "A_{2}^{3}B"; + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const string FontFamily = "Arial"; + const double FontSize = 20d; + const double FontWeight = FontWeights.Normal; + + for (var ha = HorizontalAlignment.Left; ha <= HorizontalAlignment.Right; ha++) + { + for (var va = VerticalAlignment.Top; va <= VerticalAlignment.Bottom; va++) + { + var origin = new ScreenPoint((((int)ha + 1) * 200) + 20, (((int)va + 1) * FontSize * 3) + 20); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + rc.DrawMathText(origin, text, OxyColors.Black, FontFamily, FontSize, FontWeight, 0, ha, va); + } + } + })); + return model; + } + + /// + /// Shows alignment capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Alignment/Rotation")] + public static PlotModel DrawTextAlignmentRotation() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + for (var ha = HorizontalAlignment.Left; ha <= HorizontalAlignment.Right; ha++) + { + for (var va = VerticalAlignment.Top; va <= VerticalAlignment.Bottom; va++) + { + var origin = new ScreenPoint(((int)ha + 2) * 130, ((int)va + 2) * 130); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + for (int rotation = 0; rotation < 360; rotation += 90) + { + rc.DrawText(origin, string.Format("R{0:000}", rotation), OxyColors.Black, fontSize: 20d, rotation: rotation, horizontalAlignment: ha, verticalAlignment: va); + } + } + } + })); + return model; + } + + /// + /// Shows multi-line alignment capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - Multi-line Alignment/Rotation")] + public static PlotModel DrawMultilineTextAlignmentRotation() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + for (var ha = HorizontalAlignment.Left; ha <= HorizontalAlignment.Right; ha++) + { + for (var va = VerticalAlignment.Top; va <= VerticalAlignment.Bottom; va++) + { + var origin = new ScreenPoint(((int)ha + 2) * 170, ((int)va + 2) * 170); + rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive); + for (var rotation = 0; rotation < 360; rotation += 90) + { + rc.DrawText(origin, $"R{rotation:000}\n{ha}\n{va}", OxyColors.Black, fontSize: 20d, rotation: rotation, horizontalAlignment: ha, verticalAlignment: va); + } + } + } + })); + return model; + } + + /// + /// Shows color capabilities for the DrawText method. + /// + /// A plot model. + [Example("DrawText - MaxSize")] + public static PlotModel DrawTextMaxSize() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const string Font = "Arial"; + const double FontSize = 32d; + const double FontWeight = FontWeights.Bold; + const double D = FontSize * 1.6; + const double X = 20; + const double X2 = 200; + double y = 20; + var testStrings = new[] { "iii", "jjj", "OxyPlot", "Bottom", "100", "KML" }; + foreach (var text in testStrings) + { + var maxSize = rc.MeasureText(text, Font, FontSize, FontWeight); + var p = new ScreenPoint(X, y); + rc.DrawText(p, text, OxyColors.Black, Font, FontSize, FontWeight, maxSize: maxSize); + var rect = new OxyRect(p, maxSize); + rc.DrawRectangle(rect, OxyColors.Undefined, OxyColors.Black, 1, EdgeRenderingMode.Adaptive); + + var p2 = new ScreenPoint(X2, y); + var maxSize2 = new OxySize(maxSize.Width / 2, maxSize.Height / 2); + rc.DrawText(p2, text, OxyColors.Black, Font, FontSize, FontWeight, maxSize: maxSize2); + var rect2 = new OxyRect(p2, maxSize2); + rc.DrawRectangle(rect2, OxyColors.Undefined, OxyColors.Black, 1, EdgeRenderingMode.Adaptive); + + y += D; + } + })); + return model; + } + + /// + /// Draws text and shows marks for ascent/descent/baseline/x-height and the expected bounding box. + /// + /// A plot model. + [Example("DrawText - WPF metrics")] + public static PlotModel DrawTextWithWpfMetrics() + { + return DrawTextWithMetrics("OxyPlot", "Arial", 60, 226, 69, 105, 73, 61, 116, 23, 228, "WPF"); + } + + /// + /// Draws text and shows marks for ascent/descent/baseline/x-height and the expected bounding box. + /// + /// A plot model. + [Example("DrawText - WinForms metrics (StringFormat = GenericDefault)")] + public static PlotModel DrawTextWithWinFormsMetricsDefault() + { + return DrawTextWithMetrics("OxyPlot", "Arial", 60, 252.145812988281, 79.4999847412109, 108, 73, 61, 121, 34, 252, "WinForms"); + } + + /// + /// Draws text and shows marks for ascent/descent/baseline/x-height and the expected bounding box. + /// + /// A plot model. + [Example("DrawText - WinForms metrics (StringFormat = GenericTypographic)")] + public static PlotModel DrawTextWithWinFormsMetricsTypographic() + { + return DrawTextWithMetrics("OxyPlot", "Arial", 60, 224.1, 71.5, 108, 73, 61, 121, 23, 242, "WinForms"); + } + + /// + /// Shows capabilities for the MeasureText method. + /// + /// A plot model. + [Example("MeasureText")] + public static PlotModel MeasureText() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + const string Font = "Arial"; + var strings = new[] { "OxyPlot", "MMM", "III", "jikq", "gh", "123", "!#$&" }; + var fontSizes = new[] { 10d, 20, 40, 60 }; + var x = 5d; + foreach (double fontSize in fontSizes) + { + var y = 5d; + var maxWidth = 0d; + foreach (var s in strings) + { + var size = rc.MeasureText(s, Font, fontSize); + maxWidth = Math.Max(maxWidth, size.Width); + rc.DrawRectangle(new OxyRect(x, y, size.Width, size.Height), OxyColors.LightYellow, OxyColors.Black, 1, EdgeRenderingMode.Adaptive); + rc.DrawText(new ScreenPoint(x, y), s, OxyColors.Black, Font, fontSize); + y += size.Height + 20; + } + + x += maxWidth + 20; + } + })); + return model; + } + + /// + /// Draws text with metrics. + /// + /// The text. + /// The font. + /// Size of the font. + /// The expected width. + /// The expected height. + /// The baseline position. + /// The x-height position. + /// The ascent position. + /// The descent position. + /// The before position. + /// The after position. + /// The platform. + /// + /// A plot model. + /// + public static PlotModel DrawTextWithMetrics(string text, string font, double fontSize, double expectedWidth, double expectedHeight, double baseline, double xheight, double ascent, double descent, double before, double after, string platform) + { + // http://msdn.microsoft.com/en-us/library/ms742190(v=vs.110).aspx + // http://msdn.microsoft.com/en-us/library/xwf9s90b(v=vs.110).aspx + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms533824(v=vs.85).aspx + // https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/FontHandling/FontHandling.html + var model = new PlotModel(); + model.Annotations.Add( + new DelegateAnnotation( + rc => + { + var size = rc.MeasureText(text, font, fontSize); + var expectedSize = new OxySize(expectedWidth, expectedHeight); + rc.DrawText(new ScreenPoint(300, 50), "Font size: " + fontSize, OxyColors.Black, font, 12); + rc.DrawText(new ScreenPoint(300, 70), "Actual size: " + size.ToString("0.00", CultureInfo.InvariantCulture), OxyColors.Black, font, 12); + rc.DrawText(new ScreenPoint(300, 90), "Size on " + platform + ": " + expectedSize.ToString("0.00", CultureInfo.InvariantCulture), OxyColors.Green, font, 12); + + var p = new ScreenPoint(20, 50); + rc.DrawText(p, text, OxyColors.Black, font, fontSize); + + rc.FillCircle(p, 3, OxyColors.Black, EdgeRenderingMode.Adaptive); + + // actual bounds + rc.DrawRectangle(new OxyRect(p, size), OxyColors.Undefined, OxyColors.Black, 1, EdgeRenderingMode.Adaptive); + + // Expected bounds (WPF) + rc.DrawRectangle(new OxyRect(p, expectedSize), OxyColors.Undefined, OxyColors.Green, 1, EdgeRenderingMode.Adaptive); + + var color = OxyColor.FromAColor(180, OxyColors.Red); + var pen = new OxyPen(color); + + // Expected vertical positions (WPF) + var x1 = p.X - 10; + var x2 = p.X + expectedSize.Width + 10; + rc.DrawLine(x1, baseline, x2, baseline, pen, EdgeRenderingMode.Adaptive); + rc.DrawLine(x1, xheight, x2, xheight, pen, EdgeRenderingMode.Adaptive); + rc.DrawLine(x1, ascent, x2, ascent, pen, EdgeRenderingMode.Adaptive); + rc.DrawLine(x1, descent, x2, descent, pen, EdgeRenderingMode.Adaptive); + + // Expected horizonal positions (WPF) + var y1 = p.Y - 10; + var y2 = p.Y + expectedSize.Height + 10; + rc.DrawLine(before, y1, before, y2, pen, EdgeRenderingMode.Adaptive); + rc.DrawLine(after, y1, after, y2, pen, EdgeRenderingMode.Adaptive); + })); + + model.MouseDown += (s, e) => Debug.WriteLine(e.Position); + + return model; + } + + [Example("Clipping")] + public static PlotModel Clipping() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + void DrawClipRect(OxyRect clipRect) + { + var pen = new OxyPen(OxyColors.Black, 2, LineStyle.Dash); + rc.DrawLine(clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Top, pen, EdgeRenderingMode.Automatic); + rc.DrawLine(clipRect.Right, clipRect.Top, clipRect.Right, clipRect.Bottom, pen, EdgeRenderingMode.Automatic); + rc.DrawLine(clipRect.Right, clipRect.Bottom, clipRect.Left, clipRect.Bottom, pen, EdgeRenderingMode.Automatic); + rc.DrawLine(clipRect.Left, clipRect.Bottom, clipRect.Left, clipRect.Top, pen, EdgeRenderingMode.Automatic); + } + + var currentLine = 20d; + const double lineHeight = 60; + const double clipRectSize = 40; + const double clipRectMargin = 20; + const double testCaseMargin = 20; + const double descriptionMargin = 200; + var rect = new OxyRect(); + + void DrawCircle(ScreenPoint center) + { + rc.DrawCircle(center, clipRectSize * 0.58, OxyColors.CornflowerBlue, OxyColors.Undefined, 0, EdgeRenderingMode.Automatic); + } + + void DrawDescription(string text) + { + var p = new ScreenPoint(clipRectMargin + clipRectSize + testCaseMargin + descriptionMargin, currentLine); + rc.DrawText(p, text, OxyColors.Black, fontSize: 12, verticalAlignment: VerticalAlignment.Middle); + } + + void DrawTestCase(string text) + { + var p = new ScreenPoint(clipRectMargin + clipRectSize + testCaseMargin, currentLine); + rc.DrawText(p, text, OxyColors.Black, fontSize: 12, verticalAlignment: VerticalAlignment.Middle); + } + + void DrawHeader(string text, double offset) + { + rc.DrawText(new ScreenPoint(offset, 15), text, OxyColors.Black, fontSize: 12, fontWeight: 700); + } + + void NextLine() + { + currentLine += lineHeight; + rect = new OxyRect(clipRectMargin, currentLine - clipRectSize / 2, clipRectSize, clipRectSize); + } + + DrawHeader("Actual", clipRectMargin); + DrawHeader("Test Case", clipRectMargin + clipRectSize + testCaseMargin); + DrawHeader("Expected", clipRectMargin + clipRectSize + testCaseMargin + descriptionMargin); + + //------------- + NextLine(); + rc.PushClip(rect); + rc.PopClip(); + DrawCircle(rect.Center); + + DrawTestCase("1. Push clipping rectangle\n2. Pop clipping rectangle\n3. Draw circle"); + DrawDescription("The circle should be fully drawn."); + + //------------- + NextLine(); + rc.PushClip(rect); + DrawCircle(rect.Center); + + rc.PopClip(); + + DrawClipRect(rect); + DrawTestCase("1. Push clipping rectangle\n2. Draw Circle"); + DrawDescription("The circle should be clipped."); + + //------------- + NextLine(); + var rect2 = rect.Deflate(new OxyThickness(rect.Height * 0.25)); + rc.PushClip(rect); + rc.PushClip(rect2); + + DrawCircle(rect.Center); + + rc.PopClip(); + rc.PopClip(); + + DrawClipRect(rect); + DrawClipRect(rect2); + DrawTestCase("1. Push large clipping rectangle\n2. Push small clipping rectangle\n3. Draw Circle"); + DrawDescription("The circle should be clipped to the small clipping rectangle."); + + //------------- + NextLine(); + rect2 = rect.Deflate(new OxyThickness(rect.Height * 0.25)); + rc.PushClip(rect2); + rc.PushClip(rect); + + DrawCircle(rect.Center); + + rc.PopClip(); + rc.PopClip(); + + DrawClipRect(rect); + DrawClipRect(rect2); + DrawTestCase("1. Push small clipping rectangle\n2. Push large clipping rectangle\n3. Draw Circle"); + DrawDescription("The circle should be clipped to the small clipping rectangle."); + + //------------- + NextLine(); + rect2 = rect.Offset(rect.Width / 2, rect.Height / 2).Deflate(new OxyThickness(rect.Height * 0.25)); + rc.PushClip(rect); + rc.PushClip(rect2); + + DrawCircle(rect.Center); + + rc.PopClip(); + rc.PopClip(); + + DrawClipRect(rect); + DrawClipRect(rect2); + DrawTestCase("1. Push large clipping rectangle\n2. Push small clipping rectangle\n3. Draw Circle"); + DrawDescription("The circle should be clipped to the intersection of the clipping rectangles."); + + //------------- + NextLine(); + rect2 = rect.Offset(rect.Width / 2, rect.Height / 2).Deflate(new OxyThickness(rect.Height * 0.25)); + rc.PushClip(rect); + rc.PushClip(rect2); + + rc.PopClip(); + + DrawCircle(rect.Center); + + rc.PopClip(); + + DrawClipRect(rect); + DrawClipRect(rect2); + DrawTestCase("1. Push large clipping rectangle\n2. Push small clipping rectangle\n3. Pop small clipping rectangle\n4. Draw Circle"); + DrawDescription("The circle should be clipped to the large clipping rectangle."); + + //------------- + NextLine(); + var rect3 = rect.Offset(rect.Width / 3, rect.Height / 3).Deflate(new OxyThickness(rect.Height * 0.25)); + var rect4 = rect.Offset(-rect.Width / 3, -rect.Height / 3).Deflate(new OxyThickness(rect.Height * 0.25)); + rc.PushClip(rect3); + rc.PushClip(rect4); + + DrawCircle(rect.Center); + + rc.PopClip(); + rc.PopClip(); + + DrawClipRect(rect3); + DrawClipRect(rect4); + DrawTestCase("1. Push clipping rectangle\n2. Push second clipping rectangle\n3. Draw Circle"); + DrawDescription("The circle should not be drawn at all."); + + //------------- + NextLine(); + using (rc.AutoResetClip(rect)) + { + rc.DrawText(rect.Center, "OxyPlot", OxyColors.CornflowerBlue, fontSize: 15, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + } + + DrawClipRect(rect); + DrawTestCase("1. Push clipping rectangle\n2. Draw Text"); + DrawDescription("The text should be clipped."); + })); + + return model; + } + + private const double GRID_SIZE = 40; + private const double TILE_SIZE = 30; + private const int THICKNESS_STEPS = 10; + private const double THICKNESS_STEP = .5; + private const double OFFSET_LEFT = 150; + private const double OFFSET_TOP = 20; + private static readonly OxyColor FILL_COLOR = OxyColors.LightBlue; + + [Example("Rectangles - EdgeRenderingMode")] + public static PlotModel Rectangles() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE + TILE_SIZE / 2; + var strokeThickness = i * THICKNESS_STEP; + rc.DrawText(new ScreenPoint(left, OFFSET_TOP / 2), strokeThickness.ToString(), OxyColors.Black, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + } + + foreach (EdgeRenderingMode edgeRenderingMode in Enum.GetValues(typeof(EdgeRenderingMode))) + { + var top = OFFSET_TOP + (int)edgeRenderingMode * GRID_SIZE; + rc.DrawText(new ScreenPoint(10, top + 10), edgeRenderingMode.ToString(), OxyColors.Black, verticalAlignment: VerticalAlignment.Middle); + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE; + var rect = new OxyRect(left, top, TILE_SIZE, TILE_SIZE); + var strokeThickness = i * THICKNESS_STEP; + rc.DrawRectangle(rect, FILL_COLOR, OxyColors.Black, strokeThickness, edgeRenderingMode); + } + } + + })); + return model; + } + + [Example("Lines - EdgeRenderingMode")] + public static PlotModel Lines() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE + TILE_SIZE / 2; + var strokeThickness = i * THICKNESS_STEP; + rc.DrawText(new ScreenPoint(left, OFFSET_TOP / 2), strokeThickness.ToString(), OxyColors.Black, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + } + + foreach (EdgeRenderingMode edgeRenderingMode in Enum.GetValues(typeof(EdgeRenderingMode))) + { + var top = OFFSET_TOP + (int)edgeRenderingMode * GRID_SIZE; + rc.DrawText(new ScreenPoint(10, top + 10), edgeRenderingMode.ToString(), OxyColors.Black, verticalAlignment: VerticalAlignment.Middle); + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE; + var topLeft = new ScreenPoint(left, top); + var bottomLeft = new ScreenPoint(left, top + TILE_SIZE); + var topRight = new ScreenPoint(left + TILE_SIZE, top); + var bottomRight = new ScreenPoint(left + TILE_SIZE, top + TILE_SIZE); + var middleLeft = new ScreenPoint(left, top + TILE_SIZE / 2); + var strokeThickness = i * THICKNESS_STEP; + + rc.DrawLine(new[] { bottomLeft, topLeft, topRight }, OxyColors.Black, strokeThickness, edgeRenderingMode); + rc.DrawLine(new[] { middleLeft, bottomRight, topLeft }, OxyColors.Black, strokeThickness, edgeRenderingMode, lineJoin: LineJoin.Bevel); + } + } + + })); + return model; + } + + [Example("Polygons - EdgeRenderingMode")] + public static PlotModel Polygons() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE + TILE_SIZE / 2; + var strokeThickness = i * THICKNESS_STEP; + rc.DrawText(new ScreenPoint(left, OFFSET_TOP / 2), strokeThickness.ToString(), OxyColors.Black, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + } + + foreach (EdgeRenderingMode edgeRenderingMode in Enum.GetValues(typeof(EdgeRenderingMode))) + { + var top = OFFSET_TOP + (int)edgeRenderingMode * GRID_SIZE; + rc.DrawText(new ScreenPoint(10, top + 10), edgeRenderingMode.ToString(), OxyColors.Black, verticalAlignment: VerticalAlignment.Middle); + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE; + var points = new [] + { + new ScreenPoint(left + TILE_SIZE * .4, top), + new ScreenPoint(left + TILE_SIZE, top + TILE_SIZE * .2), + new ScreenPoint(left + TILE_SIZE * .9, top + TILE_SIZE * .8), + new ScreenPoint(left + TILE_SIZE * .5, top + TILE_SIZE), + new ScreenPoint(left, top + TILE_SIZE * .6), + }; + + var strokeThickness = i * THICKNESS_STEP; + rc.DrawPolygon(points, FILL_COLOR, OxyColors.Black, strokeThickness, edgeRenderingMode); + } + } + + })); + return model; + } + + [Example("Ellipses - EdgeRenderingMode")] + public static PlotModel Ellipses() + { + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE + TILE_SIZE / 2; + var strokeThickness = i * THICKNESS_STEP; + rc.DrawText(new ScreenPoint(left, OFFSET_TOP / 2), strokeThickness.ToString(), OxyColors.Black, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + } + + foreach (EdgeRenderingMode edgeRenderingMode in Enum.GetValues(typeof(EdgeRenderingMode))) + { + var top = OFFSET_TOP + (int)edgeRenderingMode * GRID_SIZE; + rc.DrawText(new ScreenPoint(10, top + 10), edgeRenderingMode.ToString(), OxyColors.Black, verticalAlignment: VerticalAlignment.Middle); + for (int i = 0; i < THICKNESS_STEPS; i++) + { + var left = OFFSET_LEFT + i * GRID_SIZE; + var rect = new OxyRect(left, top + TILE_SIZE * .1, TILE_SIZE, TILE_SIZE * .8); + var strokeThickness = i * THICKNESS_STEP; + rc.DrawEllipse(rect, FILL_COLOR, OxyColors.Black, strokeThickness, edgeRenderingMode); + } + } + + })); + return model; + } + + [Example("LineJoin")] + public static PlotModel LineJoins() + { + const double STROKE_THICKNESS = 15; + const double LINE_LENGTH = 60; + var ANGLES = new[] { 135, 90, 45, 22.5 }; + const double COL_WIDTH = 140; + const double ROW_HEIGHT = 90; + const double ROW_HEADER_WIDTH = 50; + const double COL_HEADER_HEIGHT = 50; + + + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + var colCounter = 0; + var rowCounter = 0; + foreach (LineJoin lineJoin in Enum.GetValues(typeof(LineJoin))) + { + var p = new ScreenPoint(COL_WIDTH * (colCounter + 0.5) + ROW_HEADER_WIDTH, COL_HEADER_HEIGHT / 2); + rc.DrawText(p, lineJoin.ToString(), OxyColors.Black, fontSize: 12, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + colCounter++; + } + + foreach (var angle in ANGLES) + { + colCounter = 0; + var y = ROW_HEIGHT * rowCounter + COL_HEADER_HEIGHT; + var halfAngle = angle / 2 / 360 * 2 * Math.PI; + var dx = Math.Sin(halfAngle) * LINE_LENGTH; + var dy = Math.Cos(halfAngle) * LINE_LENGTH; + + var textP = new ScreenPoint(15, y); + rc.DrawText(textP, angle.ToString() + "°", OxyColors.Black, fontSize: 12); + + foreach (LineJoin lineJoin in Enum.GetValues(typeof(LineJoin))) + { + var x = COL_WIDTH * (colCounter + 0.5) + ROW_HEADER_WIDTH; + + var pMid = new ScreenPoint(x, y); + var p1 = new ScreenPoint(x - dx, y + dy); + var p2 = new ScreenPoint(x + dx, y + dy); + + rc.DrawLine(new[] { p1, pMid, p2 }, OxyColors.CornflowerBlue, STROKE_THICKNESS, EdgeRenderingMode.PreferGeometricAccuracy, lineJoin: lineJoin); + + colCounter++; + } + + rowCounter++; + } + + })); + return model; + } + + [Example("Ellipse Drawing")] + public static PlotModel EllipseDrawing() + { + const double RADIUS_X = 300; + const double RADIUS_Y = 100; + const double CENTER_X = RADIUS_X * 1.2; + const double CENTER_Y = RADIUS_Y * 1.2; + + var radiusXSquare = RADIUS_X * RADIUS_X; + var radiusYSquare = RADIUS_Y * RADIUS_Y; + var n = 200; + + var model = new PlotModel(); + model.Annotations.Add(new DelegateAnnotation(rc => + { + var rect = new OxyRect(CENTER_X - RADIUS_X, CENTER_Y - RADIUS_Y, RADIUS_X * 2, RADIUS_Y * 2); + + var points = new ScreenPoint[n]; + var cx = (rect.Left + rect.Right) / 2; + var cy = (rect.Top + rect.Bottom) / 2; + var rx = (rect.Right - rect.Left) / 2; + var ry = (rect.Bottom - rect.Top) / 2; + for (var i = 0; i < n; i++) + { + var a = Math.PI * 2 * i / (n - 1); + points[i] = new ScreenPoint(cx + (rx * Math.Cos(a)), cy + (ry * Math.Sin(a))); + } + + rc.DrawPolygon(points, OxyColors.Undefined, OxyColors.Black, 4, EdgeRenderingMode.PreferGeometricAccuracy); + rc.DrawEllipse(rect, OxyColors.Undefined, OxyColors.White, 2, EdgeRenderingMode.PreferGeometricAccuracy); + rc.DrawText(new ScreenPoint(CENTER_X, CENTER_Y), "The white ellipse (drawn by Renderer) should match the black ellipse (drawn as Path).", OxyColors.Black, fontSize: 12, horizontalAlignment: HorizontalAlignment.Center, verticalAlignment: VerticalAlignment.Middle); + })); + return model; + } + + /// + /// Represents an annotation that renders by a delegate. + /// + public class DelegateAnnotation : Annotation + { + /// + /// Initializes a new instance of the class. + /// + /// The rendering delegate. + public DelegateAnnotation(Action rendering) + { + this.Rendering = rendering; + } + + /// + /// Gets the rendering delegate. + /// + /// + /// The rendering. + /// + public Action Rendering { get; private set; } + + /// + /// Renders the annotation on the specified context. + /// + /// The render context. + public override void Render(IRenderContext rc) + { + base.Render(rc); + this.Rendering(rc); + } + + /// + public override OxyRect GetClippingRect() + { + return OxyRect.Everything; + } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Examples/TrackerExamples.cs b/Source/Examples/ExampleLibrary/Examples/TrackerExamples.cs new file mode 100644 index 0000000..661c277 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Examples/TrackerExamples.cs @@ -0,0 +1,117 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("Tracker")] + public static class TrackerExamples + { + [Example("No interpolation")] + public static PlotModel NoInterpolation() + { + var model = new PlotModel + { + Title = "No tracker interpolation", + Subtitle = "Used for discrete values or scatter plots.", + }; + var l = new Legend + { + LegendSymbolLength = 30 + }; + + model.Legends.Add(l); + + var s1 = new LineSeries + { + Title = "Series 1", + CanTrackerInterpolatePoints = false, + Color = OxyColors.SkyBlue, + MarkerType = MarkerType.Circle, + MarkerSize = 6, + MarkerStroke = OxyColors.White, + MarkerFill = OxyColors.SkyBlue, + MarkerStrokeThickness = 1.5 + }; + for (int i = 0; i < 63; i++) + { + s1.Points.Add(new DataPoint((int)(Math.Sqrt(i) * Math.Cos(i * 0.1)), (int)(Math.Sqrt(i) * Math.Sin(i * 0.1)))); + } + + model.Series.Add(s1); + + return model; + } + + [Example("TrackerChangedEvent")] + public static PlotModel TrackerChangedEvent() + { + var model = new PlotModel + { + Title = "Handling the TrackerChanged event", + Subtitle = "Press the left mouse button to test the tracker.", + }; + model.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 100)); + model.TrackerChanged += (s, e) => + { + model.Subtitle = e.HitResult != null ? "Tracker item index = " + e.HitResult.Index : "Not tracking"; + model.InvalidatePlot(false); + }; + return model; + } + + [Example("Specified distance of the tracker fires")] + public static Example TrackerFiresDistance() + { + var model = new PlotModel + { + Title = "Specified distance of the tracker fires", + Subtitle = "Press the left mouse button to test the tracker.", + }; + model.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 100)); + + // create a new plot controller with default bindings + var plotController = new PlotController(); + + // remove a tracker command to the mouse-left/touch down event by default + plotController.Unbind(PlotCommands.SnapTrack); + plotController.Unbind(PlotCommands.SnapTrackTouch); + + // add a tracker command to the mouse-left/touch down event with specified distance + plotController.BindMouseDown( + OxyMouseButton.Left, + new DelegatePlotCommand((view, controller, args) => + controller.AddMouseManipulator( + view, + new TrackerManipulator(view) + { + Snap = true, + PointsOnly = false, + FiresDistance = 2.0, + CheckDistanceBetweenPoints = true, + }, + args))); + plotController.BindTouchDown( + new DelegatePlotCommand((view, controller, args) => + controller.AddTouchManipulator( + view, + new TouchTrackerManipulator(view) + { + Snap = true, + PointsOnly = false, + FiresDistance = 2.0, + }, + args))); + + return new Example(model, plotController); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Issues/Issues.cs b/Source/Examples/ExampleLibrary/Issues/Issues.cs new file mode 100644 index 0000000..f2b3575 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Issues/Issues.cs @@ -0,0 +1,2583 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Threading; + using System.Threading.Tasks; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + using System.Reflection; + using System.Linq; + + [Examples("Z1 Issues")] + public class Issues + { + [Example("#1095: Issue 1095 Part 1")] + public static PlotModel IssueHalfPolarReversedAxesPart1() + { + var plotModel = new PlotModel { Title = "", }; + plotModel.PlotType = OxyPlot.PlotType.Polar; + plotModel.Axes.Add( + new AngleAxis() + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + MajorStep = 30, + MinorStep = 10, + CropGridlines = false, + StartAngle = 270 + 360, + EndAngle = 270, + Minimum = -180, + Maximum = +180, + LabelFormatter = (d) => d.ToString("F0") + }); + plotModel.Axes.Add( + new MagnitudeAxis() + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + }); + + return plotModel; + } + + [Example("#1095: Issue 1095 Part 2")] + public static PlotModel IssueHalfPolarReversedAxesPart2() + { + var plotModel = new PlotModel { Title = "", }; + plotModel.PlotType = OxyPlot.PlotType.Polar; + plotModel.Axes.Add( + new AngleAxis() + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Dot, + MajorStep = 30, + MinorStep = 10, + CropGridlines = false, + StartAngle = 180, + EndAngle = 0, + Minimum = -90, + Maximum = +90, + LabelFormatter = (d) => d.ToString("F0") + }); + plotModel.Axes.Add( + new MagnitudeAxis() + { + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + }); + + return plotModel; + } + + [Example("#91 AxisTitleDistance")] + public static PlotModel AxisTitleDistance() + { + var plotModel = new PlotModel + { + Title = "AxisTitleDistance" + }; + + var l = new Legend + { + LegendFontSize = 12, + LegendFontWeight = FontWeights.Bold + }; + + plotModel.Legends.Add(l); + + //var series = new LineSeries() { Title = "Push-Over Curve" }; + //series.Points.AddRange(pushOverPoints); + //plotModel.Series.Add(series); + + plotModel.Axes.Add(new LinearAxis + { + Title = "Base Shear", + Unit = "KN", + TitleFontSize = 12, + TitleFontWeight = FontWeights.Bold, + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + AxisTitleDistance = 15 + }); + plotModel.Axes.Add(new LinearAxis + { + Title = "Displacement", + Unit = "mm", + TitleFontSize = 12, + TitleFontWeight = FontWeights.Bold, + Position = AxisPosition.Bottom, + MajorGridlineStyle = LineStyle.Solid, + MinorGridlineStyle = LineStyle.Solid, + AxisTitleDistance = 10 + }); + return plotModel; + } + + [Example("#1044 MinimumSegmentLength not working with AreaSeries")] + public static PlotModel MinimumSegmentLengthInAreaSeries() + { + var model = new PlotModel() { Title = "MinimumSegmentLength in AreaSeries", Subtitle = "Three different areas should be visible" }; + for (var msl = 0; msl <= 200; msl += 100) + { + var series = new AreaSeries + { + Title = $"MinimumSegmentLength = {msl}", + MinimumSegmentLength = msl + }; + + for (int i = 0; i < 1000; i++) + { + series.Points.Add(new DataPoint(i, Math.Sin(i * 0.01) + 1)); + series.Points2.Add(new DataPoint(i, Math.Sin(i * 0.01))); + } + + model.Series.Add(series); + } + + return model; + } + + [Example("#1044 MinimumSegmentLength not working with LinesSeries")] + public static PlotModel MinimumSegmentLengthInLineSeries() + { + var model = new PlotModel() { Title = "MinimumSegmentLength in LineSeries", Subtitle = "Three different curves should be visible" }; + for (var msl = 0; msl <= 200; msl += 100) + { + var series = new LineSeries + { + Title = $"MinimumSegmentLength = {msl}", + MinimumSegmentLength = msl + }; + + for (int i = 0; i < 1000; i++) + { + series.Points.Add(new DataPoint(i, Math.Sin(i * 0.01))); + } + + model.Series.Add(series); + } + + return model; + } + + [Example("#1303 Problem with infinity size polyline")] + public static PlotModel InfinitySizePolyline() + { + var model = new PlotModel(); + var series = new OxyPlot.Series.LineSeries(); + series.Points.Add(new DataPoint(0, 0)); + series.Points.Add(new DataPoint(1, -1e40)); + model.Series.Add(series); + return model; + } + + [Example("#977 RectangleAnnotation Axis Clipping not configurable")] + public static PlotModel RectangleAnnotationAxisClipping() + { + var model = new PlotModel + { + Title = "RectangleAnnotation Axis Clipping", + PlotAreaBorderThickness = new OxyThickness(0), + Axes = + { + new LinearAxis + { + Position = AxisPosition.Bottom, + AxislineStyle = LineStyle.Solid, + EndPosition = 0.45 + }, + new LinearAxis + { + Position = AxisPosition.Bottom, + AxislineStyle = LineStyle.Solid, + StartPosition = 0.55, + Key = "X2" + }, + new LinearAxis + { + Position = AxisPosition.Left, + AxislineStyle = LineStyle.Solid, + EndPosition = 0.45, + }, + new LinearAxis + { + Position = AxisPosition.Left, + AxislineStyle = LineStyle.Solid, + StartPosition = 0.55, + Key = "Y2" + } + }, + Annotations = + { + new LineAnnotation + { + Type = LineAnnotationType.Vertical, + Color = OxyColors.DarkCyan, + StrokeThickness = 2, + LineStyle = LineStyle.Solid, + X = 10, + Text = "LineAnnotation (default clipping)" + }, + new LineAnnotation + { + Type = LineAnnotationType.Vertical, + Color = OxyColors.DarkGreen, + StrokeThickness = 2, + LineStyle = LineStyle.Solid, + X = 20, + ClipByYAxis = false, + Text = "LineAnnotation (ClipByYAxis = false)", + TextLinePosition = 0.5 + }, + new RectangleAnnotation + { + Fill = OxyColor.FromArgb(100, 255, 0, 0), + Stroke = OxyColors.Black, + StrokeThickness = 1, + MinimumX = 40, + MaximumX = 60, + Text = "RectangleAnnotation (default clipping)", + TextRotation = -90, + }, + new RectangleAnnotation + { + Fill = OxyColor.FromArgb(100, 0, 0, 255), + Stroke = OxyColors.Black, + StrokeThickness = 1, + MinimumX = 70, + MaximumX = 90, + ClipByYAxis = false, + Text = "RectangleAnnotation (ClipByYAxis = false)", + TextRotation = -90 + }, + new RectangleAnnotation + { + Fill = OxyColor.FromArgb(100, 0, 255, 0), + Stroke = OxyColors.Black, + StrokeThickness = 1, + MinimumY = 80, + MaximumY = 85, + Text = "RectangleAnnotation (default clipping)", + XAxisKey = "X2", + YAxisKey = "Y2" + }, + new RectangleAnnotation + { + Fill = OxyColor.FromArgb(100, 0, 255, 0), + Stroke = OxyColors.Black, + StrokeThickness = 1, + MinimumY = 90, + MaximumY = 95, + ClipByXAxis = false, + Text = "RectangleAnnotation (ClipByXAxis = false)", + XAxisKey = "X2", + YAxisKey = "Y2" + }, + new RectangleAnnotation + { + Fill = OxyColor.FromArgb(50, 100, 100, 100), + Stroke = OxyColors.Black, + StrokeThickness = 1, + MinimumX = 92, MaximumX = 140, + MinimumY = 45, MaximumY = 140, + ClipByXAxis = false, ClipByYAxis = false, + Text = "no clipping at all" + } + } + }; + return model; + } + + + [Example("Support colour coding on scatter plots (Closed)")] + public static PlotModel ColorCodingOnScatterPlots() + { + var model = new PlotModel { Title = "Colour coding on scatter plots" }; + var colorAxis = new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), Minimum = 0, Maximum = 5, HighColor = OxyColors.Gray, LowColor = OxyColors.Black }; + model.Axes.Add(colorAxis); + + var s4 = new ScatterSeries { MarkerType = MarkerType.Circle }; + s4.Points.Add(new ScatterPoint(3, 5, 5, 0)); + s4.Points.Add(new ScatterPoint(5, 5, 7, 0)); + s4.Points.Add(new ScatterPoint(2, 4, 5, 0.3)); + s4.Points.Add(new ScatterPoint(3, 3, 8, 0)); + s4.Points.Add(new ScatterPoint(3, 2, 5, 0)); + s4.Points.Add(new ScatterPoint(3, 5, 8, 1)); + s4.Points.Add(new ScatterPoint(2, 2, 3, 5)); + s4.Points.Add(new ScatterPoint(1, 4, 4, 1)); + s4.Points.Add(new ScatterPoint(4, 3, 5, 3)); + s4.Points.Add(new ScatterPoint(0, 0, 1, 1)); + s4.Points.Add(new ScatterPoint(8, 8, 1, 1)); + model.Series.Add(s4); + return model; + } + + [Example("Don't show minor ticks (Closed)")] + public static PlotModel DontShowMinorTicks() + { + var model = new PlotModel { Title = "MinorTickSize = 0" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinorTickSize = 0, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MinorTickSize = 0, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Solid }); + return model; + } + + /// + /// Grids the lines both different colors. + /// + [Example("Major grid lines in front of minor (Closed)")] + public static PlotModel GridLinesBothDifferentColors() + { + var plotModel1 = new PlotModel + { + Title = "Major grid lines in front of minor", + Subtitle = "Minor grid lines should be below major grid lines" + }; + var leftAxis = new LinearAxis + { + MajorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColors.Black, + MajorGridlineThickness = 4, + MinorGridlineStyle = LineStyle.Solid, + MinorGridlineColor = OxyColors.LightBlue, + MinorGridlineThickness = 4, + }; + plotModel1.Axes.Add(leftAxis); + var bottomAxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MajorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColors.Black, + MajorGridlineThickness = 4, + MinorGridlineStyle = LineStyle.Solid, + MinorGridlineColor = OxyColors.LightBlue, + MinorGridlineThickness = 4, + }; + plotModel1.Axes.Add(bottomAxis); + return plotModel1; + } + + [Example("#50: Sub/superscript in vertical axis title")] + public static PlotModel SubSuperScriptInAxisTitles() + { + var plotModel1 = new PlotModel { Title = "x_{i}^{j}", Subtitle = "x_{i}^{j}" }; + var leftAxis = new LinearAxis { Position = AxisPosition.Left, Title = "x_{i}^{j}" }; + plotModel1.Axes.Add(leftAxis); + var bottomAxis = new LinearAxis { Position = AxisPosition.Bottom, Title = "x_{i}^{j}" }; + plotModel1.Axes.Add(bottomAxis); + plotModel1.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 100, "x_{i}^{j}")); + return plotModel1; + } + + [Example("#50: Sub/superscript in rotated annotations")] + public static PlotModel RotatedSubSuperScript() + { + var s = "x_{A}^{B}"; + var plotModel1 = new PlotModel { Title = s, Subtitle = s }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = s, Minimum = -1, Maximum = 1 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = s, Minimum = -1, Maximum = 11 }); + for (int rotation = 0; rotation < 360; rotation += 45) + { + plotModel1.Annotations.Add(new TextAnnotation { Text = s, TextPosition = new DataPoint(rotation / 360d * 10, 0), TextRotation = rotation }); + } + + return plotModel1; + } + + [Example("#61: DateTimeAxis with IntervalType = Minutes")] + public static PlotModel DateTimeAxisWithIntervalTypeMinutes() + { + var plotModel1 = new PlotModel(); + var linearAxis1 = new LinearAxis(); + plotModel1.Axes.Add(linearAxis1); + + var dateTimeAxis1 = new DateTimeAxis + { + IntervalType = DateTimeIntervalType.Minutes, + EndPosition = 0, + StartPosition = 1, + StringFormat = "hh:mm:ss" + }; + plotModel1.Axes.Add(dateTimeAxis1); + var time0 = new DateTime(2013, 5, 6, 3, 24, 0); + var time1 = new DateTime(2013, 5, 6, 3, 28, 0); + var lineSeries1 = new LineSeries(); + lineSeries1.Points.Add(new DataPoint(DateTimeAxis.ToDouble(time0), 36)); + lineSeries1.Points.Add(new DataPoint(DateTimeAxis.ToDouble(time1), 26)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("#67: Hit testing LineSeries with smoothing")] + public static PlotModel MouseDownEvent() + { + var model = new PlotModel { Title = "LineSeries with smoothing", Subtitle = "Tracker uses wrong points" }; + var logarithmicAxis1 = new LogarithmicAxis { Position = AxisPosition.Bottom }; + model.Axes.Add(logarithmicAxis1); + + // Add a line series + var s1 = new LineSeries + { + Color = OxyColors.SkyBlue, + MarkerType = MarkerType.Circle, + MarkerSize = 6, + MarkerStroke = OxyColors.White, + MarkerFill = OxyColors.SkyBlue, + MarkerStrokeThickness = 1.5, + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline + }; + s1.Points.Add(new DataPoint(100, 100)); + s1.Points.Add(new DataPoint(400, 200)); + s1.Points.Add(new DataPoint(600, -300)); + s1.Points.Add(new DataPoint(1000, 400)); + s1.Points.Add(new DataPoint(1500, 500)); + s1.Points.Add(new DataPoint(2500, 600)); + s1.Points.Add(new DataPoint(3000, 700)); + model.Series.Add(s1); + + return model; + } + + [Example("#68: Tracker wrong for logarithmic y-axis")] + public static PlotModel ValueTime() + { + var plotModel1 = new PlotModel + { + PlotAreaBackground = OxyColors.Gray, + PlotAreaBorderColor = OxyColors.Gainsboro, + PlotAreaBorderThickness = new OxyThickness(2), + Title = "Value / Time" + }; + + var l = new Legend + { + LegendBackground = OxyColor.FromArgb(200, 255, 255, 255), + LegendBorder = OxyColors.Black, + LegendPlacement = LegendPlacement.Outside + }; + + plotModel1.Legends.Add(l); + + var linearAxis1 = new LinearAxis + { + AbsoluteMaximum = 45, + AbsoluteMinimum = 0, + Key = "X-Axis", + Maximum = 46, + Minimum = -1, + Position = AxisPosition.Bottom, + Title = "Years", + Unit = "yr" + }; + plotModel1.Axes.Add(linearAxis1); + var logarithmicAxis1 = new LogarithmicAxis { Key = "Y-Axis", Title = "Value for section" }; + plotModel1.Axes.Add(logarithmicAxis1); + var lineSeries1 = new LineSeries + { + Color = OxyColors.Red, + LineStyle = LineStyle.Solid, + MarkerFill = OxyColors.Black, + MarkerSize = 2, + MarkerStroke = OxyColors.Black, + MarkerType = MarkerType.Circle, + DataFieldX = "X", + DataFieldY = "Y", + XAxisKey = "X-Axis", + YAxisKey = "Y-Axis", + Background = OxyColors.White, + Title = "Section Value", + TrackerKey = "ValueVersusTimeTracker" + }; + lineSeries1.Points.Add(new DataPoint(0, 0)); + lineSeries1.Points.Add(new DataPoint(5, 0)); + lineSeries1.Points.Add(new DataPoint(10, 0)); + lineSeries1.Points.Add(new DataPoint(15, 0)); + lineSeries1.Points.Add(new DataPoint(20, 1)); + lineSeries1.Points.Add(new DataPoint(25, 1)); + lineSeries1.Points.Add(new DataPoint(30, 1)); + lineSeries1.Points.Add(new DataPoint(35, 1)); + lineSeries1.Points.Add(new DataPoint(40, 1)); + lineSeries1.Points.Add(new DataPoint(45, 1)); + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + [Example("AnnotationLayers (Closed)")] + public static PlotModel AnnotationLayers() + { + var model = new PlotModel { Title = "AnnotationLayers" }; + + var a1 = new RectangleAnnotation { MinimumX = 10, MaximumX = 20, MinimumY = -1, MaximumY = 1, Layer = AnnotationLayer.BelowAxes }; + var a2 = new RectangleAnnotation { MinimumX = 30, MaximumX = 40, MinimumY = -1, MaximumY = 1, Layer = AnnotationLayer.BelowSeries }; + var a3 = new RectangleAnnotation { MinimumX = 50, MaximumX = 60, MinimumY = -1, MaximumY = 1, Layer = AnnotationLayer.AboveSeries }; + model.Annotations.Add(a1); + model.Annotations.Add(a2); + model.Annotations.Add(a3); + var s1 = new FunctionSeries(Math.Sin, 0, 100, 0.01); + model.Series.Add(s1); + a1.MouseDown += (s, e) => + { + model.Subtitle = "Clicked annotation below axes"; + model.InvalidatePlot(true); + e.Handled = true; + }; + a2.MouseDown += (s, e) => + { + model.Subtitle = "Clicked annotation below series"; + model.InvalidatePlot(true); + e.Handled = true; + }; + a3.MouseDown += (s, e) => + { + model.Subtitle = "Clicked annotation above series"; + model.InvalidatePlot(true); + e.Handled = true; + }; + s1.MouseDown += (s, e) => + { + model.Subtitle = "Clicked series"; + model.InvalidatePlot(true); + e.Handled = true; + }; + + return model; + } + + [Example("Argument out of range in OxyPlot mouse over (Closed)")] + public static PlotModel ArgumentOutOfRangeInMouseOver() + { + var model = new PlotModel { Title = "Argument out of range in OxyPlot mouse over" }; + var ls = new LineSeries(); + ls.Points.Add(new DataPoint(10, 10)); + ls.Points.Add(new DataPoint(10, 10)); + ls.Points.Add(new DataPoint(12, 10)); + model.Series.Add(ls); + return model; + } + + [Example("Slow redraws with noisy data (Closed)")] + public static PlotModel NoisyData() + { + var model = new PlotModel { Title = "Noisy data" }; + + var points = new List(); + var rng = new Random(7); + for (int i = 0; i < 500; i++) + { + points.Add(new DataPoint(i + 1, rng.NextDouble())); + } + + model.Series.Add(new LineSeries { ItemsSource = points }); + return model; + } + + [Example("Dashed line test (Closed)")] + public static PlotModel DashedLineTest() + { + var model = new PlotModel { Title = "Dashed line test" }; + + for (int y = 1; y <= 24; y++) + { + var line = new LineSeries + { + StrokeThickness = y, + LineStyle = LineStyle.Dash, + Dashes = new double[] { 1, 2, 3 } // has no effect + }; + for (int i = 0; i < 20; i++) + { + line.Points.Add(new DataPoint(i + 1, y)); + } + + model.Series.Add(line); + } + + return model; + } + + [Example("Super exponential format (Closed)")] + public static PlotModel SuperExponentialFormat() + { + var model = new PlotModel { Title = "UseSuperExponentialFormat=true and 0" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100, MajorStep = 10, MinorStep = 1, UseSuperExponentialFormat = true }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -100, Maximum = 100, MajorStep = 20, MinorStep = 10, UseSuperExponentialFormat = true }); + return model; + } + + [Example("AreaSeries draws on top of other elements (Closed)")] + public static PlotModel DefaultAnnotationLayer() + { + var plotModel1 = new PlotModel { Title = "Annotations should be drawn on top by default", Subtitle = "The line annotation should be on top!" }; + var areaSeries1 = new AreaSeries(); + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 40)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + areaSeries1.Points2.Add(new DataPoint(0, 60)); + areaSeries1.Points2.Add(new DataPoint(5, 80)); + areaSeries1.Points2.Add(new DataPoint(20, 70)); + areaSeries1.Color = OxyColors.Red; + areaSeries1.Color2 = OxyColors.Blue; + areaSeries1.Fill = OxyColors.Yellow; + + plotModel1.Series.Add(areaSeries1); + var lineAnnotation = new LineAnnotation + { + Type = LineAnnotationType.Vertical, + Layer = AnnotationLayer.AboveSeries, + X = 6 + }; + + plotModel1.Annotations.Add(lineAnnotation); + return plotModel1; + } + + [Example("#79: LegendItemAlignment = Center (closed)")] + public static PlotModel LegendItemAlignmentCenter() + { + var plotModel1 = new PlotModel { Title = "LegendItemAlignment = Center" }; + var l = new Legend + { + LegendItemAlignment = HorizontalAlignment.Center, + LegendBorder = OxyColors.Black, + LegendBorderThickness = 1 + }; + + plotModel1.Legends.Add(l); + + plotModel1.Series.Add(new FunctionSeries(x => Math.Sin(x) / x, 0, 10, 100, "sin(x)/x")); + plotModel1.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 100, "cos(x)")); + return plotModel1; + } + + [Example("AreaSeries should respect CanTrackerInterpolatePoints (Closed)")] + public static PlotModel AreaSeries_CanTrackerInterpolatePointsFalse() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with CanTrackerInterpolatePoints=false" }; + var areaSeries1 = new AreaSeries { CanTrackerInterpolatePoints = false }; + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 40)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + areaSeries1.Points2.Add(new DataPoint(0, 60)); + areaSeries1.Points2.Add(new DataPoint(5, 80)); + areaSeries1.Points2.Add(new DataPoint(20, 70)); + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("AreaSeries should respect CanTrackerInterpolatePoints=true (Closed)")] + public static PlotModel AreaSeries_CanTrackerInterpolatePointsTrue() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with CanTrackerInterpolatePoints=true" }; + var areaSeries1 = new AreaSeries { CanTrackerInterpolatePoints = true }; + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 40)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + areaSeries1.Points2.Add(new DataPoint(0, 60)); + areaSeries1.Points2.Add(new DataPoint(5, 80)); + areaSeries1.Points2.Add(new DataPoint(20, 70)); + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("GetNearestPoint return DataPoint even when custom IDataPoint used (closed)")] + public static PlotModel GetNearestPointReturnsDataPoint() + { + var plotModel1 = new PlotModel { Title = "GetNearestPoint" }; + //// TODO: add code to reproduce + return plotModel1; + } + + [Example("#102: Selecting points changes the legend colours")] + public static PlotModel SelectingPointsChangesTheLegendColors() + { + var plotModel1 = new PlotModel { Title = "Selecting points changes the legend colours" }; + //// TODO: add code to reproduce + return plotModel1; + } + + [Example("Empty LineSeries with smoothing (Closed)")] + public static PlotModel EmptyLineSeriesWithSmoothing_ThrowsException() + { + var plotModel1 = new PlotModel { Title = "Empty LineSeries with smoothing" }; + plotModel1.Series.Add(new LineSeries + { + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline + }); + return plotModel1; + } + + [Example("#119: Data points remain visible outside of bounds on panning")] + public static PlotModel DataPointsRemainVisibleOutsideBoundsOnPanning() + { + var plotModel1 = new PlotModel(); + + var masterAxis = new DateTimeAxis { Key = "MasterDateTimeAxis", Position = AxisPosition.Bottom }; + plotModel1.Axes.Add(masterAxis); + + var verticalAxis = new LinearAxis + { + Position = AxisPosition.Left, + Title = "Measurement", + Key = "Measurement", + AbsoluteMinimum = -100, + Minimum = -100, + AbsoluteMaximum = 100, + Maximum = 100, + IsZoomEnabled = false, + IsPanEnabled = false + }; + + plotModel1.Axes.Add(verticalAxis); + + var line = new LineSeries { Title = "Measurement", XAxisKey = masterAxis.Key, YAxisKey = verticalAxis.Key }; + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), 10)); + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(1)), 10)); + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(2)), 45)); + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(3)), 17)); + + line.Points.Add(DataPoint.Undefined); + + // this point should be visible + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(4)), 10)); + //// line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(4)), 10)); + + line.Points.Add(DataPoint.Undefined); + + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(5)), 45)); + line.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now.AddSeconds(6)), 17)); + + plotModel1.Series.Add(line); + + return plotModel1; + } + + [Example("Floating-point inaccuracy (Closed)")] + public static PlotModel FloatingPointInaccuracy() + { + var model = new PlotModel { Title = "Floating-point inaccuracy" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -0.0515724495834661, Maximum = 0.016609368598352, MajorStep = 0.02, MinorStep = 0.002 }); + return model; + } + + [Example("LineSeries.Dashes property (Closed)")] + public static PlotModel DashesTest() + { + var model = new PlotModel { Title = "Dashed line test" }; + + for (int y = 1; y <= 10; y++) + { + var line = new LineSeries + { + StrokeThickness = y, + Dashes = new double[] { 1, 2, 3 } + }; + for (int i = 0; i < 20; i++) + { + line.Points.Add(new DataPoint(i + 1, y)); + } + + model.Series.Add(line); + } + + return model; + } + + [Example("ScatterSeries and LinearColorAxis on the same plot (Closed)")] + public static PlotModel ScatterSeriesAndLinearColorAxis() + { + var plotModel = new PlotModel { Title = "ScatterSeries and LinearColorAxis on the same plot" }; + int npoints = 100; + var random = new Random(); + + var scatterSeries = new ScatterSeries { ColorAxisKey = string.Empty }; + for (var i = 0; i < npoints; i++) + { + scatterSeries.Points.Add(new ScatterPoint((double)i / npoints, random.NextDouble())); + } + + plotModel.Series.Add(scatterSeries); + + var lineSeries = new LineSeries(); + for (var i = 0; i < npoints; i++) + { + lineSeries.Points.Add(new DataPoint((double)i / npoints, random.NextDouble())); + } + + plotModel.Series.Add(lineSeries); + + plotModel.Axes.Add(new LinearColorAxis()); + return plotModel; + } + + [Example("#133: MinorStep should not be MajorStep/5 when MajorStep is 2")] + public static PlotModel MinorTicks() + { + var plotModel1 = new PlotModel { Title = "Issue 10117" }; + plotModel1.Axes.Add(new LinearAxis { Minimum = 0, Maximum = 16 }); + return plotModel1; + } + + [Example("Scatterseries not rendered at specific plot sizes (closed)")] + public static PlotModel ScatterSeries() + { + var plotModel1 = new PlotModel + { + Title = "Scatterseries not rendered at specific plot sizes", + PlotMargins = new OxyThickness(50, 5, 5, 50), + Padding = new OxyThickness(0), + PlotAreaBorderThickness = new OxyThickness(1, 1, 1, 1), + PlotAreaBorderColor = OxyColors.Black, + TextColor = OxyColors.Black + }; + + var l = new Legend + { + LegendOrientation = LegendOrientation.Horizontal, + LegendPosition = LegendPosition.TopRight, + LegendMargin = 0 + }; + + plotModel1.Legends.Add(l); + + plotModel1.Axes.Add(new LinearAxis + { + IsAxisVisible = true, + Title = "X", + Position = AxisPosition.Bottom, + TickStyle = TickStyle.Outside, + TicklineColor = OxyColors.Black, + Minimum = 0, + MaximumPadding = 0.05 + }); + plotModel1.Axes.Add(new LogarithmicAxis + { + MinimumPadding = 0.05, + MaximumPadding = 0.1, + Title = "Y", + Position = AxisPosition.Left, + TickStyle = TickStyle.Outside, + TicklineColor = OxyColors.Black, + MajorGridlineColor = OxyColors.Black, + MajorGridlineStyle = LineStyle.Solid + }); + var referenceCurve = new LineSeries + { + Title = "Reference", + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + Color = OxyColor.FromArgb(255, 89, 128, 168) + }; + var upperBoundary = new LineSeries + { + LineStyle = LineStyle.Dot, + Color = OxyColors.LightGray, + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + Title = string.Empty + }; + + var lowerBoundary = new LineSeries + { + LineStyle = LineStyle.Dot, + Color = OxyColors.LightGray, + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + Title = "+/- 15 %" + }; + + // Series that holds and formats points inside of the boundary + var inBoundaryResultLine = new ScatterSeries + { + Title = "actual", + MarkerFill = OxyColors.Black, + MarkerSize = 4, + MarkerStroke = OxyColors.White, + MarkerType = MarkerType.Circle + }; + + // Series that holds and formats points outside of the boundary + var outBoundaryResultLine = new ScatterSeries + { + Title = "not permissible deviation", + MarkerFill = OxyColors.Red, + MarkerSize = 4, + MarkerStroke = OxyColors.White, + MarkerType = MarkerType.Circle + }; + + // Just some random data to fill the series: + var referenceValues = new[] + { + double.NaN, 0.985567558024852, 0.731704530257957, 0.591109071735532, 0.503627816316065, 0.444980686815776, + 0.403576666032678, 0.373234299823915, 0.350375591667333, 0.332795027566349, 0.319063666439909, + 0.30821748743148, 0.299583943726489, 0.292680371378706, 0.287151885046283, 0.282732008216725, + 0.279216923371711, 0.276557880999918 + }; + var actualValues = new[] + { + double.NaN, 0.33378346040897, 1.09868427497967, 0.970771068054048, 0.739778217457323, 0.582112938330166, + 0.456962500853806, 0.37488740614826, 0.330272509496142, 0.334461549522006, 0.30989175806678, + 0.286944862053553, 0.255895385950234, 0.231850970296068, 0.217579897050944, 0.217113227224437, + 0.164759946945322, 0.0459134254747994 + }; + + for (var index = 0; index <= 17; index++) + { + var referenceValue = referenceValues[index]; + var lowerBound = referenceValue - (referenceValue * 0.15); + var upperBound = referenceValue + (referenceValue * 0.15); + referenceCurve.Points.Add(new DataPoint(index, referenceValue)); + lowerBoundary.Points.Add(new DataPoint(index, lowerBound)); + upperBoundary.Points.Add(new DataPoint(index, upperBound)); + + var actualValue = actualValues[index]; + if (actualValue > lowerBound && actualValue < upperBound) + { + inBoundaryResultLine.Points.Add(new ScatterPoint(index, actualValue)); + } + else + { + outBoundaryResultLine.Points.Add(new ScatterPoint(index, actualValue)); + } + } + + plotModel1.Series.Add(referenceCurve); + plotModel1.Series.Add(lowerBoundary); + plotModel1.Series.Add(upperBoundary); + plotModel1.Series.Add(outBoundaryResultLine); + plotModel1.Series.Add(inBoundaryResultLine); + + return plotModel1; + } + + [Example("ScatterSeries with invalid point and marker type circle (closed)")] + public static PlotModel ScatterSeriesWithInvalidPointAndMarkerTypeCircle() + { + var plotModel1 = new PlotModel + { + Title = "ScatterSeries with invalid point and marker type circle", + }; + plotModel1.Series.Add(new ScatterSeries + { + MarkerType = MarkerType.Circle, + ItemsSource = new[] { new ScatterPoint(0, double.NaN), new ScatterPoint(0, 0) } + }); + return plotModel1; + } + + [Example("RectangleBarSeries rendered on top layer (rejected)")] + public static PlotModel RectangleBarSeriesRenderedOnTopLayer() + { + var plotModel1 = new PlotModel + { + Title = "RectangleBarSeries rendered on top layer", + }; + var lineSeries1 = new LineSeries(); + lineSeries1.Points.Add(new DataPoint(0, 1)); + lineSeries1.Points.Add(new DataPoint(1, 0)); + plotModel1.Series.Add(lineSeries1); + var rectangleBarSeries1 = new RectangleBarSeries(); + rectangleBarSeries1.Items.Add(new RectangleBarItem(0.25, 0.25, 0.75, 0.75)); + plotModel1.Series.Add(rectangleBarSeries1); + var lineSeries2 = new LineSeries(); + lineSeries2.Points.Add(new DataPoint(0, 0)); + lineSeries2.Points.Add(new DataPoint(1, 1)); + plotModel1.Series.Add(lineSeries2); + return plotModel1; + } + + [Example("Legend is not visible (closed)")] + public static PlotModel LegendIsNotVisible() + { + var plotModel = new PlotModel + { + Title = "Legend is not visible", + }; + plotModel.Series.Add(new LineSeries { Title = "LineSeries 1" }); + plotModel.Series.Add(new LineSeries { Title = "LineSeries 2" }); + plotModel.Series.Add(new LineSeries { Title = "LineSeries 3" }); + plotModel.IsLegendVisible = true; + var l = new Legend + { + LegendPlacement = LegendPlacement.Inside, + LegendPosition = LegendPosition.RightMiddle, + LegendOrientation = LegendOrientation.Vertical + }; + + plotModel.Legends.Add(l); + return plotModel; + } + + [Example("#189: Wrong position of titles when PositionAtZeroCrossing is true")] + public static PlotModel PositionAtZeroCrossing() + { + var plotModel1 = new PlotModel { PlotType = PlotType.Cartesian, Title = "Zero Crossing Diagram", Subtitle = "The titles should be shown next to the axes" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, AxislineStyle = LineStyle.Solid, PositionAtZeroCrossing = true, Title = "horizontal axis" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, AxislineStyle = LineStyle.Solid, PositionAtZeroCrossing = true, Title = "vertical axis" }); + plotModel1.Series.Add(new FunctionSeries(x => Math.Cos(x * Math.PI / 180.0) * 2, x => Math.Sin(x * Math.PI / 180.0) * 2, 0.0, 180.0, 1.0) + { + Color = OxyColors.Red + }); + + return plotModel1; + } + + [Example("#189: PositionAtZeroCrossing and no plot area border")] + public static PlotModel PositionAtZeroCrossingNoPlotBorder() + { + var pm = PositionAtZeroCrossing(); + pm.PlotAreaBorderThickness = new OxyThickness(0); + pm.Subtitle = "The axis lines should be drawn when the origin is outside the plot area."; + return pm; + } + + [Example("#185: Wrong plot margins when Angle = 90 (LinearAxis)")] + public static PlotModel PlotMarginsLinearAxisWhenAxisAngleIs90() + { + var plotModel1 = new PlotModel { Title = "Plot margins not adjusted correctly when Angle = 90", Subtitle = "The numbers should not be clipped" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Angle = 90, Minimum = 1e8, Maximum = 1e9 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Angle = 90, Minimum = 1e8, Maximum = 1e9 }); + return plotModel1; + } + + [Example("#185: Wrong plot margins when Angle = 90 (DateTimeAxis)")] + public static PlotModel PlotMarginsDateTimeAxisWhenAxisAngleIs90() + { + var plotModel1 = new PlotModel { Title = "Plot margins not adjusted correctly when Angle = 90", Subtitle = "The numbers should not be clipped" }; + plotModel1.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, Angle = 90 }); + plotModel1.Axes.Add(new DateTimeAxis { Position = AxisPosition.Left, Angle = 90 }); + return plotModel1; + } + + [Example("#180: Two vertical axes on the same position")] + public static PlotModel TwoVerticalAxisOnTheSamePosition() + { + var plotModel1 = new PlotModel { Title = "Two vertical axes on the same position", Subtitle = "The titles should overlap here!" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "First axis" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Second axis" }); + return plotModel1; + } + + [Example("#180: Two vertical axis on the same position (Start/EndPosition)")] + public static PlotModel TwoVerticalAxisOnTheSamePositionStartEndPosition() + { + var plotModel1 = new PlotModel { Title = "Two vertical axes on the same position with different StartPosition/EndPosition", Subtitle = "The titles should be centered on the axes" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 0, EndPosition = 0.4, Title = "First axis" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 0.6, EndPosition = 1, Title = "Second axis" }); + return plotModel1; + } + + [Example("#180: Two vertical axis on the same position (PositionTier)")] + public static PlotModel TwoVerticalAxisOnTheSamePositionStartEndPositionPositionTier() + { + var plotModel1 = new PlotModel { Title = "Two vertical axes on the same position with different PositionTier", Subtitle = "The titles should be centered and not overlapping" }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, PositionTier = 0, Title = "First axis" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, PositionTier = 1, Title = "Second axis", AxislineStyle = LineStyle.Solid }); + return plotModel1; + } + + [Example("#220: Tracker strings not correctly showing date/times (closed)")] + public static PlotModel TrackerStringsNotCorrectlySHowingDateTimes() + { + var plotModel1 = new PlotModel { Title = "Tracker strings not correctly showing date/times" }; + plotModel1.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, Title = "Date" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Quantity" }); + var ls = new LineSeries { TrackerFormatString = "{1}: {2:d-M-yyyy}\n{3}: {4:0.00}", MarkerType = MarkerType.Circle }; + var t0 = new DateTime(2014, 10, 16); + for (int i = 0; i < 20; i++) + { + ls.Points.Add(new DataPoint(DateTimeAxis.ToDouble(t0.AddDays(i)), 13 + Math.IEEERemainder(i, 7))); + } + + plotModel1.Series.Add(ls); + return plotModel1; + } + + [Example("#226: LineSeries exception when smoothing")] + public static PlotModel LineSeriesExceptionWhenSmoothing() + { + var plotModel1 = new PlotModel + { + Title = "LineSeries null reference exception when smoothing is enabled and all datapoints have the same y value", + Subtitle = "Click on the plot to reproduce the issue." + }; + var ls = new LineSeries + { + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + }; + ls.Points.Add(new DataPoint(0, 0)); + ls.Points.Add(new DataPoint(1, 0)); + ls.Points.Add(new DataPoint(10, 0)); + plotModel1.Series.Add(ls); + return plotModel1; + } + + [Example("#79: Center aligned legends (closed)")] + public static PlotModel CenterAlignedLegends() + { + var plotModel1 = new PlotModel + { + Title = "Center aligned legends" + }; + + var l = new Legend + { + LegendPosition = LegendPosition.BottomCenter, + LegendItemAlignment = HorizontalAlignment.Center + }; + + plotModel1.Legends.Add(l); + + plotModel1.Series.Add(new LineSeries { Title = "LineSeries 1" }); + plotModel1.Series.Add(new LineSeries { Title = "LS2" }); + return plotModel1; + } + + [Example("#356: Draw legend line with custom pattern")] + public static PlotModel LegendWithCustomPattern() + { + var plotModel1 = new PlotModel + { + Title = "Draw legend line with custom pattern", + }; + var solid = new LineSeries + { + Title = "Solid", + LineStyle = LineStyle.Solid + // without dashes + }; + var custom = new LineSeries + { + Title = "Custom", + LineStyle = LineStyle.Solid, + // dashd-dot pattern + Dashes = new[] { 10.0, 2.0, 4.0, 2.0 }, + }; + solid.Points.Add(new DataPoint(0, 2)); + solid.Points.Add(new DataPoint(100, 1)); + custom.Points.Add(new DataPoint(0, 3)); + custom.Points.Add(new DataPoint(100, 2)); + plotModel1.Series.Add(solid); + plotModel1.Series.Add(custom); + + var l = new Legend + { + LegendSymbolLength = 100 // wide enough to see pattern + }; + + plotModel1.Legends.Add(l); + return plotModel1; + } + + [Example("#409: ImageAnnotation width width/height crashes")] + public static PlotModel ImageAnnotationWithWidthHeightCrashes() + { + var myModel = new PlotModel { Title = "Example 1" }; + myModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)")); + + var rng = new Random(); + var buf = new byte[100, 100]; + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + buf[i, j] = (byte)rng.Next(); + } + } + + var palette = new OxyColor[256]; + for (int i = 0; i < palette.Length; i++) + { + palette[i] = OxyColor.FromArgb(128, (byte)i, 0, 0); + } + + var image = OxyImage.Create(buf, palette, ImageFormat.Bmp); + myModel.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + + X = new PlotLength(1, PlotLengthUnit.Data), + Y = new PlotLength(0, PlotLengthUnit.Data), + Width = new PlotLength(1, PlotLengthUnit.Data), + Height = new PlotLength(1, PlotLengthUnit.Data) + }); + + myModel.Annotations.Add(new ImageAnnotation + { + ImageSource = image, + + X = new PlotLength(5, PlotLengthUnit.Data), + Y = new PlotLength(0, PlotLengthUnit.Data), + }); + + return myModel; + } + + [Example("#413: HeatMap tracker format string")] + public static PlotModel HeatMapTrackerFormatString() + { + var plotModel1 = new PlotModel + { + Title = "HeatMap tracker format string", + }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StringFormat = "0.000", Minimum = 0, Maximum = 1 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StringFormat = "0.000", Minimum = 0, Maximum = 1 }); + plotModel1.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Minimum = 0, Maximum = 5 }); + var data = new double[,] { { 1, 2 }, { 3, 4 } }; + plotModel1.Series.Add(new HeatMapSeries + { + Data = data, + CoordinateDefinition = HeatMapCoordinateDefinition.Edge, + X0 = 0.1, + X1 = 0.9, + Y0 = 0.1, + Y1 = 0.9, + TrackerFormatString = "{0}\n{1}: {2:0.000}\n{3}: {4:0.000}\n{5}: {6:0.0000}" + }); + return plotModel1; + } + + [Example("#413: Using axis format strings in tracker")] + public static PlotModel AxisFormatStringInTracker() + { + var plotModel1 = new PlotModel + { + Title = "Using axis format strings in tracker", + }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StringFormat = "0.000", Minimum = 0, Maximum = 1 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StringFormat = "0.000", Minimum = 0, Maximum = 1 }); + plotModel1.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Minimum = 0, Maximum = 5 }); + var data = new double[,] { { 1, 2 }, { 3, 4 } }; + plotModel1.Series.Add(new HeatMapSeries + { + Data = data, + CoordinateDefinition = HeatMapCoordinateDefinition.Edge, + X0 = 0.1, + X1 = 0.9, + Y0 = 0.1, + Y1 = 0.9, + + // IDEA: add new arguments for axis formatted values + // TODO: this will throw an exception, argument 7 and 8 is not implemented + TrackerFormatString = "{0}\n{1}: {7}\n{3}: {8}\n{5}: {6:0.0000}" + }); + return plotModel1; + } + + [Example("#408: CategoryAxis label clipped on left margin")] + public static PlotModel CategoryAxisLabelClipped() + { + var plotModel1 = new PlotModel + { + Title = "CategoryAxis label clipped on left margin", + }; + var axis = new CategoryAxis { Position = AxisPosition.Left, Angle = -52 }; + axis.Labels.Add("Very very very very long label"); + axis.Labels.Add("Short label"); + axis.Labels.Add("Short label"); + axis.Labels.Add("Short label"); + plotModel1.Axes.Add(axis); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + return plotModel1; + } + + private class TimeValue + { + public DateTime Time { get; set; } + public double Value { get; set; } + } + + [Example("#474: Vertical Axis Title Font Bug")] + public static PlotModel VerticalAxisTitleFontBug() + { + var plotModel1 = new PlotModel + { + Title = "Vertical Axis Title Font Bug", + }; + + plotModel1.Axes.Add(new LinearAxis + { + Title = "X_Axe", + Position = AxisPosition.Bottom, + MajorGridlineStyle = LineStyle.Solid, + TitleFont = "Times New Roman" + }); + + plotModel1.Axes.Add(new LinearAxis + { + Title = "Y_Axe", + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.Solid, + TitleFont = "Times New Roman" + }); + + return plotModel1; + } + + + [Example("#535: Transposed HeatMap")] + public static PlotModel TransposedHeatMap() + { + int n = 100; + + double x0 = -3.1; + double x1 = 3.1; + double y0 = -3; + double y1 = 3; + Func peaks = (x, y) => 3 * (1 - x) * (1 - x) * Math.Exp(-(x * x) - (y + 1) * (y + 1)) - 10 * (x / 5 - x * x * x - y * y * y * y * y) * Math.Exp(-x * x - y * y) - 1.0 / 3 * Math.Exp(-(x + 1) * (x + 1) - y * y); + var xvalues = ArrayBuilder.CreateVector(x0, x1, n); + var yvalues = ArrayBuilder.CreateVector(y0, y1, n); + var peaksData = ArrayBuilder.Evaluate(peaks, xvalues, yvalues); + + var model = new PlotModel { Title = "Normal Heatmap" }; + + model.Axes.Add( + new LinearAxis() { Key = "x_axis", AbsoluteMinimum = x0, AbsoluteMaximum = x1, Position = AxisPosition.Left }); + + model.Axes.Add( + new LinearAxis() { Key = "y_axis", AbsoluteMinimum = y0, AbsoluteMaximum = y1, Position = AxisPosition.Top }); + + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + var hms = new HeatMapSeries + { + X0 = x0, + X1 = x1, + Y0 = y0, + Y1 = y1, + Data = peaksData, + XAxisKey = "x_axis", + YAxisKey = "y_axis" + }; + model.Series.Add(hms); + + return model; + } + + [Example("#535: Normal HeatMap")] + public static PlotModel NormalHeatMap() + { + int n = 100; + + double x0 = -3.1; + double x1 = 3.1; + double y0 = -3; + double y1 = 3; + Func peaks = (x, y) => 3 * (1 - x) * (1 - x) * Math.Exp(-(x * x) - (y + 1) * (y + 1)) - 10 * (x / 5 - x * x * x - y * y * y * y * y) * Math.Exp(-x * x - y * y) - 1.0 / 3 * Math.Exp(-(x + 1) * (x + 1) - y * y); + var xvalues = ArrayBuilder.CreateVector(x0, x1, n); + var yvalues = ArrayBuilder.CreateVector(y0, y1, n); + var peaksData = ArrayBuilder.Evaluate(peaks, xvalues, yvalues); + + var model = new PlotModel { Title = "Peaks" }; + + model.Axes.Add( + new LinearAxis() { Key = "x_axis", AbsoluteMinimum = x0, AbsoluteMaximum = x1, Position = AxisPosition.Top }); + + model.Axes.Add( + new LinearAxis() { Key = "y_axis", AbsoluteMinimum = y0, AbsoluteMaximum = y1, Position = AxisPosition.Left }); + + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + var hms = new HeatMapSeries + { + X0 = x0, + X1 = x1, + Y0 = y0, + Y1 = y1, + Data = peaksData, + XAxisKey = "x_axis", + YAxisKey = "y_axis" + }; + model.Series.Add(hms); + + return model; + } + + [Example("#1065: LinearColorAxis Title")] + public static PlotModel ColorAxisTitle() + { + int n = 100; + + double x0 = -3.1; + double x1 = 3.1; + double y0 = -3; + double y1 = 3; + Func peaks = (x, y) => 3 * (1 - x) * (1 - x) * Math.Exp(-(x * x) - (y + 1) * (y + 1)) - 10 * (x / 5 - x * x * x - y * y * y * y * y) * Math.Exp(-x * x - y * y) - 1.0 / 3 * Math.Exp(-(x + 1) * (x + 1) - y * y); + var xvalues = ArrayBuilder.CreateVector(x0, x1, n); + var yvalues = ArrayBuilder.CreateVector(y0, y1, n); + var peaksData = ArrayBuilder.Evaluate(peaks, xvalues, yvalues); + + var model = new PlotModel { Title = "Peaks" }; + + model.Axes.Add(new LinearAxis() { Key = "x_axis", AbsoluteMinimum = x0, AbsoluteMaximum = x1, Position = AxisPosition.Top }); + + model.Axes.Add(new LinearAxis() { Key = "y_axis", AbsoluteMinimum = y0, AbsoluteMaximum = y1, Position = AxisPosition.Left }); + + model.Axes.Add(new LinearColorAxis { Title = "wrong Placement", Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + var hms = new HeatMapSeries + { + X0 = x0, + X1 = x1, + Y0 = y0, + Y1 = y1, + Data = peaksData, + XAxisKey = "x_axis", + YAxisKey = "y_axis" + }; + model.Series.Add(hms); + + return model; + } + + /// + /// Contains example code for https://github.com/oxyplot/oxyplot/issues/42 + /// + /// The plot model. + [Example("#42: ContourSeries not working for not square data array")] + public static PlotModel IndexOutOfRangeContour() + { + var model = new PlotModel { Title = "Issue #42" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(5) }); + + var x = ArrayBuilder.CreateVector(0, 1, 20); + var y = ArrayBuilder.CreateVector(-1, 1, 2); + var data = ArrayBuilder.Evaluate((a, b) => a * b, x, y); + + var contour = new ContourSeries + { + ColumnCoordinates = y, + RowCoordinates = x, + Data = data + }; + model.Series.Add(contour); + + return model; + } + + [Example("#624: Rendering math text with syntax error gets stuck in an endless loop")] + public static PlotModel MathTextWithSyntaxError() + { + var model = new PlotModel { Title = "Math text syntax errors" }; + model.Series.Add(new LineSeries { Title = "x_{1" }); + model.Series.Add(new LineSeries { Title = "x^{2" }); + model.Series.Add(new LineSeries { Title = "x^{2_{1" }); + model.Series.Add(new LineSeries { Title = "x^{ x^" }); + model.Series.Add(new LineSeries { Title = "x_{ x_" }); + model.Series.Add(new LineSeries { Title = "" }); + model.Series.Add(new LineSeries { Title = "x^{ x_{ x^_" }); + return model; + } + + [Example("#19: The minimum value is not mentioned on the axis I")] + public static PlotModel MinimumValueOnAxis() + { + var model = new PlotModel { Title = "Show minimum and maximum values on axis" }; + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + //ShowMinimumValue = true, + //ShowMaximumValue = true, + //MinimumValueStringFormat = "0.###", + //MaximumValueStringFormat = "0.###", + MaximumPadding = 0, + MinimumPadding = 0 + }); + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + //ShowMinimumValue = true, + //ShowMaximumValue = true, + //MinimumValueStringFormat = "0.###", + //MaximumValueStringFormat = "0.###", + MaximumPadding = 0, + MinimumPadding = 0 + }); + var ls = new LineSeries(); + ls.Points.Add(new DataPoint(0.14645, 0.14645)); + ls.Points.Add(new DataPoint(9.85745, 9.85745)); + model.Series.Add(ls); + return model; + } + + [Example("#19: The minimum value is not mentioned on the axis II")] + public static PlotModel MinimumValueOnAxis2() + { + var model = new PlotModel { Title = "Show minimum and maximum values on axis" }; + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + //ShowMinimumValue = true, + //ShowMaximumValue = true, + //MinimumValueStringFormat = "0.###", + //MaximumValueStringFormat = "0.###", + MaximumPadding = 0, + MinimumPadding = 0 + }); + model.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + //ShowMinimumValue = true, + //ShowMaximumValue = true, + //MinimumValueStringFormat = "0.###", + //MaximumValueStringFormat = "0.###", + MaximumPadding = 0, + MinimumPadding = 0 + }); + var ls = new LineSeries(); + ls.Points.Add(new DataPoint(-0.14645, -0.14645)); + ls.Points.Add(new DataPoint(10.15745, 10.15745)); + model.Series.Add(ls); + return model; + } + + [Example("#550: MinimumRange with Minimum")] + public static PlotModel MinimumRangeWithMinimum() + { + var model = new PlotModel { Title = "MinimumRange of 500 with a Minimum of 50", Subtitle = "Should initially show a range from 50 to 550." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 50, + MinimumRange = 500 + }); + + return model; + } + + + [Example("#710: MinimumRange and MaximumRange with Minimum")] + public static PlotModel MinimumRangeAndMaximumRangeWithMinimum() + { + var model = new PlotModel { Title = "MinimumRange of 5 and MaximumRange of 200 with a Minimum of 0", Subtitle = "Should show a range from 0 to 5 minimum and a range of 200 maximum." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + MinimumRange = 5, + MaximumRange = 200 + }); + + return model; + } + + [Example("#711: MinimumRange with AbsoluteMinimum")] + public static PlotModel MinimumRangeWithAbsoluteMinimum() + { + var model = new PlotModel { Title = "MinimumRange of 500 with a AbsoluteMinimum of 50", Subtitle = "Should initially show a range from 50 to 550. It should not be possible to pan below 50." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + AbsoluteMinimum = 50, + MinimumRange = 500 + }); + + return model; + } + + [Example("#711: MinimumRange with AbsoluteMaximum")] + public static PlotModel MinimumRangeWithAbsoluteMaximum() + { + var model = new PlotModel { Title = "MinimumRange of 500 with a AbsoluteMaximum of 200", Subtitle = "Should initially show a range from -300 to 200. It should not be possible to pan above 200." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + AbsoluteMaximum = 200, + MinimumRange = 500 + }); + + return model; + } + + [Example("#711: MaximumRange with AbsoluteMinimum")] + public static PlotModel MaximumRangeWithAbsoluteMinimum() + { + var model = new PlotModel { Title = "MaximumRange of 50 with a AbsoluteMinimum of 20", Subtitle = "Should initially show a range from 20 to 70. It should not be possible to pan below 20." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + AbsoluteMinimum = 20, + MaximumRange = 50 + }); + + return model; + } + + [Example("#711: MaximumRange with AbsoluteMaximum")] + public static PlotModel MaximumRangeWithAbsoluteMaximum() + { + var model = new PlotModel { Title = "MaximumRange of 25 with a AbsoluteMaximum of -20", Subtitle = "Should initially show a range from -45 to -20. It should not be possible to pan above -20." }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + AbsoluteMaximum = -20, + MaximumRange = 25 + }); + + return model; + } + + [Example("#745: HeatMap not working in Windows Universal")] + public static PlotModel PlotHeatMap() + { + var model = new PlotModel { Title = "FOOBAR" }; + model.Axes.Add(new LinearColorAxis + { + Position = AxisPosition.Right, + Palette = OxyPalettes.Jet(500), + HighColor = OxyColors.Gray, + LowColor = OxyColors.Black + }); + + var data = new double[,] { { 1, 2 }, { 1, 1 }, { 2, 1 }, { 2, 2 } }; + + var hs = new HeatMapSeries + { + Background = OxyColors.Red, + X0 = 0, + X1 = 2, + Y0 = 0, + Y1 = 3, + Data = data, + }; + model.Series.Add(hs); + return model; + } + + [Example("#758: IntervalLength = 0")] + public static PlotModel IntervalLength0() + { + var model = new PlotModel + { + Title = "IntervalLength = 0", + Subtitle = "An exception should be thrown. Should not go into infinite loop." + }; + model.Axes.Add(new LinearAxis { IntervalLength = 0 }); + return model; + } + + [Example("#737: Wrong axis line when PositionAtZeroCrossing = true")] + public static PlotModel WrongAxisLineWhenPositionAtZeroCrossingIsSet() + { + var model = new PlotModel { Title = "PositionAtZeroCrossing" }; + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left + }); + model.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Bottom, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + AxislineThickness = 1 + }); + var lineSeries = new LineSeries(); + lineSeries.Points.Add(new DataPoint(-10, 10)); + lineSeries.Points.Add(new DataPoint(0, -10)); + lineSeries.Points.Add(new DataPoint(10, 10)); + model.Series.Add(lineSeries); + return model; + } + + [Example("#727: Axis Min/Max ignored")] + public static PlotModel AxisMinMaxIgnored() + { + var plotModel1 = new PlotModel + { + Title = "Axes min/max ignored", + PlotType = PlotType.Cartesian, + }; + var ls = new LineSeries(); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 866, Key = "Horizontal" }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 103, Maximum = 37141, Key = "Vertical" }); + ls.XAxisKey = "Horizontal"; + ls.YAxisKey = "Vertical"; + plotModel1.Series.Add(ls); + + return plotModel1; + } + + [Example("#727: Axis Min/Max")] + public static PlotModel AxisMinMax() + { + var plotModel1 = new PlotModel + { + Title = "Axes min/max", + }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 866 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 103, Maximum = 37141 }); + + return plotModel1; + } + + /// + /// Creates a demo PlotModel with MinimumRange defined + /// and with series with values which are within this range. + /// + /// The created PlotModel + [Example("#794: Axis alignment when MinimumRange is set")] + public static PlotModel MinimumRangeTest() + { + var model = new PlotModel(); + var yaxis = new LinearAxis() + { + Position = AxisPosition.Left, + MinimumRange = 1, + }; + + model.Axes.Add(yaxis); + + var series = new LineSeries(); + series.Points.Add(new DataPoint(0, 10.1)); + series.Points.Add(new DataPoint(1, 10.15)); + series.Points.Add(new DataPoint(2, 10.3)); + series.Points.Add(new DataPoint(3, 10.25)); + series.Points.Add(new DataPoint(4, 10.1)); + + model.Series.Add(series); + + return model; + } + + [Example("#72: Smooth")] + public static PlotModel Smooth() + { + var model = new PlotModel { Title = "LineSeries with Smooth = true (zoomed in)" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new LineSeries { InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline }; + s1.Points.Add(new DataPoint(0, 0)); + s1.Points.Add(new DataPoint(10, 2)); + s1.Points.Add(new DataPoint(40, 1)); + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 10.066564180257437, Maximum = 10.081628088306001 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 2.0013430243084067, Maximum = 2.00209808854281 }); + return model; + } + + [Example("#880: Too much padding")] + public static PlotModel TooMuchPadding() + { + return new PlotModel { Title = "Too much padding", Padding = new OxyThickness(0, 0, 0, 10000) }; + } + + [Example("#880: Too much padding with legend outside")] + public static PlotModel TooMuchPaddingWithLegend() + { + var model = new PlotModel + { + Title = "Too much padding with legend outside", + Padding = new OxyThickness(500) + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + model.Series.Add(new LineSeries { Title = "Series 1" }); + model.Series.Add(new LineSeries { Title = "Series 2" }); + return model; + } + + [Example("#880: Too much title padding")] + public static PlotModel TooMuchTitlePadding() + { + var model = new PlotModel { Title = "Too much title padding", TitlePadding = 10000 }; + return model; + } + + /// + /// Creates a demo PlotModel with MinimumRange defined + /// and with series with values which are within this range. + /// + /// The created PlotModel + [Example("#794: Axis alignment when MinimumRange is set with AbsoluteMaximum")] + public static PlotModel MinimumRangeAbsoluteMaximumTest() + { + var model = new PlotModel(); + var yaxis = new LinearAxis() + { + Position = AxisPosition.Left, + MinimumRange = 1, + AbsoluteMaximum = 10.5 + }; + + model.Axes.Add(yaxis); + + var series = new LineSeries(); + series.Points.Add(new DataPoint(0, 10.1)); + series.Points.Add(new DataPoint(1, 10.15)); + series.Points.Add(new DataPoint(2, 10.3)); + series.Points.Add(new DataPoint(3, 10.25)); + series.Points.Add(new DataPoint(4, 10.1)); + + model.Series.Add(series); + + return model; + } + + /// + /// Creates a demo PlotModel with MinimumRange defined + /// and with series with values which are within this range. + /// + /// The created PlotModel + [Example("#794: Axis alignment when MinimumRange is set with AbsoluteMinimum")] + public static PlotModel MinimumRangeAbsoluteMinimumTest() + { + var model = new PlotModel(); + var yaxis = new LinearAxis() + { + Position = AxisPosition.Left, + MinimumRange = 1, + AbsoluteMinimum = 10, + }; + + model.Axes.Add(yaxis); + + var series = new LineSeries(); + series.Points.Add(new DataPoint(0, 10.1)); + series.Points.Add(new DataPoint(1, 10.15)); + series.Points.Add(new DataPoint(2, 10.3)); + series.Points.Add(new DataPoint(3, 10.25)); + series.Points.Add(new DataPoint(4, 10.1)); + + model.Series.Add(series); + + return model; + } + + /// + /// Creates a demo PlotModel with the data from the issue. + /// + /// The created PlotModel + [Example("#589: LogarithmicAxis glitches with multiple series containing small data")] + public static PlotModel LogaritmicAxesSuperExponentialFormatTest() + { + var model = new PlotModel(); + model.Axes.Add(new LogarithmicAxis + { + UseSuperExponentialFormat = true, + Position = AxisPosition.Bottom, + MajorGridlineStyle = LineStyle.Dot, + PowerPadding = true + }); + + model.Axes.Add(new LogarithmicAxis + { + UseSuperExponentialFormat = true, + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.Dot, + PowerPadding = true + }); + + var series1 = new LineSeries(); + series1.Points.Add(new DataPoint(1e5, 1e-14)); + series1.Points.Add(new DataPoint(4e7, 1e-12)); + model.Series.Add(series1); + + return model; + } + + /// + /// Attempts to create a logarithmic axis starting at 1 and going to 0. + /// + /// The plot model. + [Example("#925: WPF app freezes when LogarithmicAxis is reversed.")] + public static PlotModel LogarithmicAxisReversed() + { + var model = new PlotModel(); + model.Axes.Add(new LogarithmicAxis { StartPosition = 1, EndPosition = 0 }); + + return model; + } + + [Example("#1029: LineAnnotation (loglin axes)")] + public static PlotModel Issue1029LogLin() + { + var plotModel1 = new PlotModel + { + Title = "Possible Infinite Loop in LineAnnotation.GetPoints() when Minimum=Maximum", + }; + plotModel1.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 10 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 8 }); + plotModel1.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Vertical, X = 4, MinimumY = 2, MaximumY = 2 }); + plotModel1.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Horizontal, Y = 2, MinimumX = 2, MaximumX = 2 }); + return plotModel1; + } + + [Example("#1029: LineAnnotation (linlin axes)")] + public static PlotModel Issue1029LinLin() + { + var plotModel1 = new PlotModel + { + Title = "Possible Infinite Loop in LineAnnotation.GetPoints() when Minimum=Maximum", + }; + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 10 }); + plotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 8 }); + plotModel1.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Vertical, X = 4, MinimumY = 2, MaximumY = 2 }); + plotModel1.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Horizontal, Y = 2, MinimumX = 2, MaximumX = 2 }); + return plotModel1; + } + + /// + /// Creates a plot model as described in issue 1090. + /// + /// The plot model. + [Example("#1090: Overflow when zoomed in on logarithmic scale")] + public static PlotModel Issue1090() + { + var plotModel = new PlotModel(); + plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, AbsoluteMinimum = 0 }); + plotModel.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left }); + + return plotModel; + } + + [Example("#1132: ScatterSeries with TimeSpanAxis")] + public static PlotModel ScatterSeriesWithTimeSpanAxis() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new TimeSpanAxis { Position = AxisPosition.Bottom }); + plotModel1.Axes.Add(new TimeSpanAxis { Position = AxisPosition.Left }); + + var points = new[] + { + new TimeSpanPoint { X = TimeSpan.FromSeconds(0), Y = TimeSpan.FromHours(1) }, + new TimeSpanPoint { X = TimeSpan.FromSeconds(0), Y = TimeSpan.FromHours(1) } + }; + + plotModel1.Series.Add(new ScatterSeries { ItemsSource = points, DataFieldX = "X", DataFieldY = "Y" }); + + return plotModel1; + } + + [Example("#1132: ScatterSeries with DateTimeAxis")] + public static PlotModel ScatterSeriesWithDateTimeAxis() + { + var plotModel1 = new PlotModel(); + plotModel1.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom }); + plotModel1.Axes.Add(new DateTimeAxis { Position = AxisPosition.Left }); + + var points = new[] + { + new DateTimePoint { X = new DateTime(2017,10,10), Y = new DateTime(2017,10,11) }, + new DateTimePoint { X = new DateTime(2017,1,1), Y = new DateTime(2018,1,1) } + }; + + plotModel1.Series.Add(new ScatterSeries { ItemsSource = points, DataFieldX = "X", DataFieldY = "Y" }); + + return plotModel1; + } + + [Example("#1160: Exporting TextAnnotation with transparent TextColor to SVG produces opaque text")] + public static PlotModel ExportTransparentTextAnnotationToSvg() + { + var plot = new PlotModel(); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + plot.Background = OxyColors.Black; + plot.Annotations.Add(new TextAnnotation + { + TextPosition = new DataPoint(25, 0), + Text = "Opaque", + TextColor = OxyColor.FromRgb(255, 0, 0), + FontSize = 10, + }); + plot.Annotations.Add(new TextAnnotation + { + TextPosition = new DataPoint(25, 20), + Text = "Semi transparent", + TextColor = OxyColor.FromArgb(125, 255, 0, 0), + FontSize = 10, + }); + plot.Annotations.Add(new TextAnnotation + { + TextPosition = new DataPoint(25, 40), + Text = "Transparent1", + TextColor = OxyColor.FromArgb(0, 255, 0, 0), + FontSize = 10, + }); + plot.Annotations.Add(new TextAnnotation + { + TextPosition = new DataPoint(25, 60), + Text = "Transparent2", + TextColor = OxyColors.Transparent, + FontSize = 10, + }); + + return plot; + } + + [Example("#1312: Annotations ignore LineStyle.None and draw as if Solid")] + public static PlotModel DrawArrowAnnotationsWithDifferentLineStyles() + { + LineStyle[] lineStyles = new[] + { + LineStyle.Solid, + LineStyle.Dash, + LineStyle.Dot, + LineStyle.DashDot, + LineStyle.DashDashDot, + LineStyle.DashDotDot, + LineStyle.DashDashDotDot, + LineStyle.LongDash, + LineStyle.LongDashDotDot, + LineStyle.None, + LineStyle.Automatic + }; + + var plot = new PlotModel() { Title = "Annotation Line Styles", Subtitle = "'None' should produce nothing" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = lineStyles.Length * 10 + 10 }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100 }); + + double y = 10; + foreach (var lineStyle in lineStyles) + { + plot.Annotations.Add(new LineAnnotation() + { + LineStyle = lineStyle, + Type = LineAnnotationType.Horizontal, + Y = y, + MinimumX = 10, + MaximumX = 45 + }); + + plot.Annotations.Add(new ArrowAnnotation() + { + LineStyle = lineStyle, + Text = lineStyle.ToString(), + TextHorizontalAlignment = HorizontalAlignment.Center, + TextVerticalAlignment = VerticalAlignment.Bottom, + TextPosition = new DataPoint(50, y), + StartPoint = new DataPoint(55, y), + EndPoint = new DataPoint(90, y) + }); + + y += 10; + } + + return plot; + } + + [Example("#1385: GraphicsRenderContext sometimes clips last line of text")] + public static PlotModel DrawMultilineText() + { + var plot = new PlotModel() { Title = "GraphicsRenderContext\nsometimes clips last\nline of text" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100 }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100 }); + + double y = 0.0; + for (int i = 2; i < 50; i++) + { + plot.Annotations.Add(new TextAnnotation() { Text = "GraphicsRenderContext\nsometimes clips last\nline of text", TextPosition = new DataPoint(50, y += i), FontSize = i }); + } + + return plot; + } + + [Example("#1441: Zero crossing quadrant axes disappear on zoom and pan (Closed)")] + public static PlotModel ZeroCrossingQuadrantAxes() + { + var plot = new PlotModel() { Title = "Zoom or Pan axes to make them disappear" }; + + var xaxis = new LinearAxis + { + Position = AxisPosition.Top, + PositionTier = 0, + AxislineStyle = LineStyle.Solid, + Minimum = 0, + AxislineColor = OxyColors.Red, + StartPosition = 0.5, + EndPosition = 1, + PositionAtZeroCrossing = true, + AbsoluteMinimum = 0, + Title = "ABC", + + }; + plot.Axes.Add(xaxis); + + var xaxis2 = new LinearAxis + { + Position = AxisPosition.Top, + PositionTier = 0, + AxislineStyle = LineStyle.Solid, + Minimum = 0, + AxislineColor = OxyColors.Gold, + StartPosition = 0.5, + EndPosition = 0, + PositionAtZeroCrossing = true, + IsAxisVisible = true, + AbsoluteMinimum = 0, + Title = "DCS", + + }; + plot.Axes.Add(xaxis2); + + var yaxis = new LinearAxis + { + Position = AxisPosition.Left, + AxislineStyle = LineStyle.Solid, + Minimum = 0, + AxislineColor = OxyColors.Green, + PositionTier = 0, + StartPosition = 0.5, + EndPosition = 1, + PositionAtZeroCrossing = true, + AbsoluteMinimum = 0, + AbsoluteMaximum = 1000, + Title = "DSDC", + + }; + plot.Axes.Add(yaxis); + + var yaxis2 = new LinearAxis + { + Position = AxisPosition.Right, + AxislineStyle = LineStyle.Solid, + Minimum = 0, + AxislineColor = OxyColors.Violet, + PositionTier = 0, + StartPosition = 0.5, + EndPosition = 0, + PositionAtZeroCrossing = true, + AbsoluteMinimum = 0, + + }; + plot.Axes.Add(yaxis2); + + plot.PlotAreaBorderThickness = new OxyThickness(1, 1, 1, 1); + + return plot; + } + + [Example("#1524: HitTracker IndexOutOfRangeException with HeatMapSeries")] + public static PlotModel HitTrackerIndexOutOfRangeExceptionWithHeatMapSeries() + { + List xAxisLabels = new List() { "1", "2", "3", "4", "5", "1", "2", "3", "4", "5" }; + List yAxisLabels = new List() { "1", "2", "3", "4", "5", "1", "2", "3", "4", "5" }; + + var plot = new PlotModel() { Title = "Place the tracker to the far top or right of the series\nwith a small window size." }; + + List jetTransparent = new List(); + foreach (var item in OxyPalettes.Jet(1000).Colors) + { + jetTransparent.Add(OxyColor.FromAColor(220, item)); + } + OxyPalette myPalette = new OxyPalette(jetTransparent); + + plot.PlotAreaBackground = OxyColors.White; + plot.DefaultFontSize = 14; + //plotModel.DefaultColors = SeriesColors; + plot.Padding = new OxyThickness(0); + plot.TitlePadding = 0; + + + plot.Axes.Add(new CategoryAxis + { + Position = AxisPosition.Bottom, + Key = "HorizontalAxis", + ItemsSource = xAxisLabels, + MajorGridlineColor = OxyColors.Black, + MajorGridlineStyle = LineStyle.Solid, + IsZoomEnabled = false, + IsPanEnabled = false, + Angle = -45, + FontSize = 14, + TitleFontSize = 14, + AxisTitleDistance = 0 + }); + + plot.Axes.Add(new CategoryAxis + { + Position = AxisPosition.Left, + Key = "VerticalAxis", + ItemsSource = yAxisLabels, + MajorGridlineColor = OxyColors.Black, + MajorGridlineStyle = LineStyle.Solid, + IsZoomEnabled = false, + IsPanEnabled = false, + FontSize = 14, + TitleFontSize = 14 + }); + + // Color axis + plot.Axes.Add(new LinearColorAxis() + { + Palette = myPalette, + }); + + var rand = new Random(); + var data = new double[yAxisLabels.Count, xAxisLabels.Count]; + for (int x = 0; x < xAxisLabels.Count; ++x) + { + for (int y = 0; y < yAxisLabels.Count; ++y) + { + data[y, x] = rand.Next(0, 200) * (0.13876876848794587508758879 * (y + 1)); + } + } + + var heatMapSeries = new HeatMapSeries + { + X0 = 0, + X1 = xAxisLabels.Count - 1, + Y0 = 0, + Y1 = yAxisLabels.Count - 1, + XAxisKey = "HorizontalAxis", + YAxisKey = "VerticalAxis", + RenderMethod = HeatMapRenderMethod.Bitmap, + Interpolate = true, + Data = data, + TrackerFormatString = "{3}: {4}\n{1}: {2}\n{5}: {6:N1}%", + }; + + plot.Series.Add(heatMapSeries); + + return plot; + } + + [Example("#1545: Some render contexts do not support unix line endings.")] + public static PlotModel UnixLineEndings() + { + var plot = new PlotModel() { Title = "Some render contexts\r\ndo not support\nunix line endings." }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100 }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100 }); + + plot.Annotations.Add(new TextAnnotation() { Text = "CRLF\r\nLine\r\nEndings", TextPosition = new DataPoint(16, 50), FontSize = 12 }); + plot.Annotations.Add(new TextAnnotation() { Text = "LF\nLine\nEndings", TextPosition = new DataPoint(50, 50), FontSize = 12 }); + plot.Annotations.Add(new TextAnnotation() { Text = "Mixed\r\nLine\nEndings", TextPosition = new DataPoint(84, 50), FontSize = 12 }); + + return plot; + } + + [Example("#1481: Emoji text.")] + public static PlotModel EmojiText() + { + var plot = new PlotModel() { Title = "🖊 Emoji plot 📈" }; + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 100 }); + plot.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 100 }); + + plot.Annotations.Add(new TextAnnotation() { Text = "0 ❗ 1 📊 2 ❗ 3 📊 4 ❗ 5 📊 6 ❗ 7 📊 8 ❗ 9 📊", TextPosition = new DataPoint(50, 80), FontSize = 12 }); + plot.Annotations.Add(new TextAnnotation() { Text = "0 ❗ 1 📊 2 ❗ 3 📊 4 ❗ 5 📊 6 ❗ 7 📊 8 ❗ 9 📊", TextPosition = new DataPoint(50, 50), FontSize = 12, TextRotation = 45 }); + + return plot; + } + + [Example("#1512: FindWindowStartIndex.")] + public static PlotModel FindWindowsStartIndex() + { + var plotModel1 = new PlotModel { Title = "AreaSeries broken in time" }; + var axis = new LinearAxis {Position = AxisPosition.Left, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0}; + var xAxis = new LinearAxis() {Position = AxisPosition.Bottom, Minimum = 4}; + + plotModel1.Axes.Add(axis); + plotModel1.Axes.Add(xAxis); + + var N = 15; + var random = new Random(6); + var currentValue = random.NextDouble() - 0.5; + var areaSeries = new AreaSeries(); + for (int i = 0; i < N; ++i) + { + if (random.Next(4) == 0) + { + areaSeries.Points.Add(DataPoint.Undefined); + areaSeries.Points2.Add(DataPoint.Undefined); + } + + currentValue += random.NextDouble(); + areaSeries.Points.Add(new DataPoint(currentValue, currentValue)); + areaSeries.Points2.Add(new DataPoint(currentValue, currentValue)); + } + + plotModel1.Series.Add(areaSeries); + + + return plotModel1; + } + + [Example("#1441: Near-border axis line clipping (Closed)")] + public static PlotModel ZeroCrossingWithInsertHorizontalAxisAndTransparentBorder() + { + var plotModel1 = new PlotModel + { + Title = "PositionAtZeroCrossing = true", + Subtitle = "Horizontal axis StartPosition = 0.1 End Position = 0.9", + PlotAreaBorderThickness = new OxyThickness(5), + PlotAreaBorderColor = OxyColor.FromArgb(127, 127, 127, 127), + PlotMargins = new OxyThickness(10, 10, 10, 10) + }; + plotModel1.Axes.Add(new LinearAxis + { + Minimum = -100, + Maximum = 100, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Crossing + }); + plotModel1.Axes.Add(new LinearAxis + { + Minimum = -100, + Maximum = 100, + Position = AxisPosition.Bottom, + PositionAtZeroCrossing = true, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Crossing, + StartPosition = 0.9, + EndPosition = 0.1 + }); + + var scatter = new ScatterSeries(); + var rnd = new Random(0); + for (int i = 0; i < 100; i++) + { + scatter.Points.Add(new ScatterPoint(rnd.NextDouble() * 100 - 50, rnd.NextDouble() * 100 - 50)); + } + plotModel1.Series.Add(scatter); + + return plotModel1; + } + + [Example("#1659: Last line of series titles in legend not displayed in Chinese on WinForms (Closed)")] + public static PlotModel LastLineOfSeriesTitlesNotDisplayedInChineseOnWindows() + { + var plot = new PlotModel() { Title = "#1659: Last line of series titles in legend not displayed in Chinese on WinForms" }; + + plot.Legends.Add(new Legend() { LegendTitle = "漂亮的天鹅" }); + plot.Series.Add(new FunctionSeries(x => x, 0, 1, 0.1, "漂亮的天鹅")); + plot.Series.Add(new FunctionSeries(x => x, 0, 1, 0.1, "漂亮的天鹅\n友好的天鹅")); + plot.Series.Add(new FunctionSeries(x => x, 0, 1, 0.1, "漂亮的天鹅\n友好的天鹅\n尼斯天鹅")); + + return plot; + } + + [Example("#1685: ContourSeries produce fake connections")] + public static PlotModel ContourSeriesProduceFakeConnections() + { + var plot = new PlotModel(); + + var data = new double[64, 64]; + using (var stream = typeof(Issues).GetTypeInfo().Assembly.GetManifestResourceStream("ExampleLibrary.Resources.DodgyContourData.tsv")) + { + using (var reader = new System.IO.StreamReader(stream)) + { + for (int r = 0; r < data.GetLength(0); r++) + { + var line = reader.ReadLine(); + var row = line.Split('\t'); + + for (int c = 0; c < data.GetLength(0); c++) + { + data[r, c] = double.Parse(row[c]); + } + } + } + } + + var xs = new double[64]; + using (var stream = typeof(Issues).GetTypeInfo().Assembly.GetManifestResourceStream("ExampleLibrary.Resources.X.txt")) + { + using (var reader = new System.IO.StreamReader(stream)) + { + for (int i = 0; i < xs.Length; i++) + { + var line = reader.ReadLine(); + xs[i] = double.Parse(line); + } + } + } + + var ys = new double[64]; + using (var stream = typeof(Issues).GetTypeInfo().Assembly.GetManifestResourceStream("ExampleLibrary.Resources.Y.txt")) + { + using (var reader = new System.IO.StreamReader(stream)) + { + for (int i = 0; i < ys.Length; i++) + { + var line = reader.ReadLine(); + ys[i] = double.Parse(line); + } + } + } + + double[] contourLevels = { 0.2, 0.4, 0.6, 0.8, 0.9, 1.0 }; + double maxi = data.Max2D(); + + double[] tmp = new double[contourLevels.Length]; + for (int i = 0; i < contourLevels.Length; i++) + { + tmp[i] = maxi * contourLevels[i]; + } + + var xaxis = new LogarithmicAxis() { Position = AxisPosition.Bottom }; + var yaxis = new LogarithmicAxis() { Position = AxisPosition.Left }; + var caxis = new LinearColorAxis() { Position = AxisPosition.Right, Palette = OxyPalettes.Gray(100) }; + + plot.Axes.Add(xaxis); + plot.Axes.Add(yaxis); + plot.Axes.Add(caxis); + + var hs = new HeatMapSeries + { + Data = data, + X0 = xs.First(), + X1 = xs.Last(), + Y0 = ys.First(), + Y1 = ys.Last(), + CoordinateDefinition = HeatMapCoordinateDefinition.Center, + }; + + var cs = new ContourSeries + { + TextColor = OxyColors.Transparent, + LabelBackground = OxyColors.Transparent, + ContourLevels = tmp, + Data = data, + ColumnCoordinates = xs, + RowCoordinates = ys, + }; + + plot.Series.Add(hs); + plot.Series.Add(cs); + + return plot; + } + + [Example("#1716: DateTimeAxis sometimes ignores IntervalLength")] + public static PlotModel DateTimeAxisSometimesIgnoresIntervalLength() + { + var plot = new PlotModel(); + + plot.Title = "IntervalLength is ignored for large ranges with IntervalType of Years or Weeks"; + + var days = new DateTimeAxis + { + IntervalType = DateTimeIntervalType.Days, + Position = AxisPosition.Bottom, + PositionTier = 1, + Minimum = DateTimeAxis.ToDouble(new DateTime(2000, 1, 1)), + Maximum = DateTimeAxis.ToDouble(new DateTime(2001, 1, 1)), + Title = "Days (mostly fine)", + }; + + var weeks = new DateTimeAxis + { + IntervalType = DateTimeIntervalType.Weeks, + Position = AxisPosition.Bottom, + PositionTier = 2, + Minimum = DateTimeAxis.ToDouble(new DateTime(2000, 1, 1)), + Maximum = DateTimeAxis.ToDouble(new DateTime(2001, 1, 1)), + Title = "Weeks (nothing is fine)", + }; + + var years = new DateTimeAxis + { + IntervalType = DateTimeIntervalType.Years, + Position = AxisPosition.Bottom, + PositionTier = 3, + Minimum = DateTimeAxis.ToDouble(new DateTime(2000, 1, 1)), + Maximum = DateTimeAxis.ToDouble(new DateTime(2100, 1, 1)), + Title = "Years (minor ticks not fine)", + }; + + plot.Axes.Add(days); + plot.Axes.Add(weeks); + plot.Axes.Add(years); + + return plot; + } + + [Example("#1982: Area series GetNearestPoint Issue")] + public static PlotModel Issue1982AreaSeriesGetNearestPoint() + { + var plotModel1 = new PlotModel() + { + Subtitle = "AreaSeries.GetNearestPoint returns nonsense indexes, and doesn't snap to the nearest point." + }; + + AreaSeries areaSeries = new AreaSeries(); + areaSeries.TrackerFormatString = "Y: {4:0.#####}\nX: {2:0.#####}\nZ: {Z}"; + + CustomDataPoint[] CdpTest = new CustomDataPoint[1000]; + for (int i = 0; i < 1000; i++) + { + // Z corresponds to the item index + CdpTest[i] = new CustomDataPoint(x: i, (i - 500) * (i - 500), i); + } + + areaSeries.ItemsSource = CdpTest; + plotModel1.Series.Add(areaSeries); + + areaSeries.CanTrackerInterpolatePoints = false; + + return plotModel1; + } + + private class TimeSpanPoint + { + public TimeSpan X { get; set; } + public TimeSpan Y { get; set; } + } + + private class DateTimePoint + { + public DateTime X { get; set; } + public DateTime Y { get; set; } + } + + public class CustomDataPoint : IDataPointProvider + { + public double X { get; } + public double Y { get; } + public int Z { get; } + + public CustomDataPoint(double x, double y, int z) + { + X = x; + Y = y; + Z = z; + } + + public DataPoint GetDataPoint() + { + return new DataPoint(X, Y); + } + } + + /* NEW ISSUE TEMPLATE + [Example("#123: Issue Description")] + public static PlotModel IssueDescription() + { + var plotModel1 = new PlotModel + { + Title = "", + }; + + return plotModel1; + } + */ + } +} diff --git a/Source/Examples/ExampleLibrary/Misc/MiscExamples.cs b/Source/Examples/ExampleLibrary/Misc/MiscExamples.cs new file mode 100644 index 0000000..76044b8 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Misc/MiscExamples.cs @@ -0,0 +1,2395 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Appends the specified target. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Reflection; + using System.Threading; + using System.Threading.Tasks; + using System.Xml.Serialization; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + using System.Linq; + + [Examples("Misc")] + public static class MiscExamples + { + [Example("Numeric ODE solvers (y'=y)")] + public static PlotModel NumericOdeSolvers1() + { + return NumericOdeSolvers("Numeric ODE solvers", "y'=y, y(0)=1", 0, 1, Math.Exp, (t, y) => y); + } + + [Example("Numeric ODE solvers (y'=x)")] + public static PlotModel NumericOdeSolvers2() + { + return NumericOdeSolvers("Numeric ODE solvers", "y'=x, y(0)=0", 0, 0, t => 0.5 * t * t, (t, y) => t); + } + + [Example("Numeric ODE solvers (y'=cos(x))")] + public static PlotModel NumericOdeSolvers3() + { + return NumericOdeSolvers("Numeric ODE solvers", "y'=cos(x), y(0)=0", 0, 0, Math.Sin, (t, y) => Math.Cos(t)); + } + + public static PlotModel NumericOdeSolvers( + string title, + string subtitle, + double t0, + double y0, + Func exact, + Func f) + { + var model = new PlotModel + { + Title = title, + Subtitle = subtitle, + }; + + var l = new Legend + { + LegendPosition = LegendPosition.BottomCenter, + LegendPlacement = LegendPlacement.Outside, + LegendOrientation = LegendOrientation.Horizontal + }; + + model.Legends.Add(l); + model.Series.Add(new FunctionSeries(exact, 0, 4, 100) { Title = "Exact solution", StrokeThickness = 5 }); + var eulerSeries = new LineSeries + { + Title = "Euler, h=0.25", + MarkerType = MarkerType.Circle, + MarkerFill = OxyColors.Black, + }; + eulerSeries.Points.AddRange(Euler(f, t0, y0, 4, 0.25)); + model.Series.Add(eulerSeries); + + //model.Series.Add(new LineSeries("Euler, h=1") + // { + // MarkerType = MarkerType.Circle, + // MarkerFill = OxyColors.Black, + // Points = Euler(f, t0, y0, 4, 1) + // }); + var heunSeries = new LineSeries + { + Title = "Heun, h=0.25", + MarkerType = MarkerType.Circle, + MarkerFill = OxyColors.Black, + }; + heunSeries.Points.AddRange(Heun(f, t0, y0, 4, 0.25)); + model.Series.Add(heunSeries); + + var midpointSeries = new LineSeries + { + Title = "Midpoint, h=0.25", + MarkerType = MarkerType.Circle, + MarkerFill = OxyColors.Black, + }; + midpointSeries.Points.AddRange(Midpoint(f, t0, y0, 4, 0.25)); + model.Series.Add(midpointSeries); + + var rkSeries = new LineSeries + { + Title = "RK4, h=0.25", + MarkerType = MarkerType.Circle, + MarkerFill = OxyColors.Black, + }; + rkSeries.Points.AddRange(RungeKutta4(f, t0, y0, 4, 0.25)); + model.Series.Add(rkSeries); + + //model.Series.Add(new LineSeries("RK4, h=1") + //{ + // MarkerType = MarkerType.Circle, + // MarkerFill = OxyColors.Black, + // Points = RungeKutta4(f, t0, y0, 4, 1) + //}); + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + return model; + } + + private static List Euler( + Func f, double t0, double y0, double t1, double h) + { + var points = new List(); + double y = y0; + for (double t = t0; t < t1 + h / 2; t += h) + { + points.Add(new DataPoint(t, y)); + y += h * f(t, y); + } + + return points; + } + + private static IList Heun(Func f, double t0, double y0, double t1, double h) + { + var points = new List(); + double y = y0; + for (double t = t0; t < t1 + h / 2; t += h) + { + points.Add(new DataPoint(t, y)); + double ytilde = y + h * f(t, y); + y = y + h / 2 * (f(t, y) + f(t + h, ytilde)); + } + + return points; + } + + private static List Midpoint( + Func f, double t0, double y0, double t1, double h) + { + var points = new List(); + double y = y0; + for (double t = t0; t < t1 + h / 2; t += h) + { + points.Add(new DataPoint(t, y)); + y += h * f(t + h / 2, y + h / 2 * f(t, y)); + } + + return points; + } + + private static List RungeKutta4( + Func f, double t0, double y0, double t1, double h) + { + var points = new List(); + double y = y0; + for (double t = t0; t < t1 + h / 2; t += h) + { + points.Add(new DataPoint(t, y)); + double k1 = h * f(t, y); + double k2 = h * f(t + h / 2, y + k1 / 2); + double k3 = h * f(t + h / 2, y + k2 / 2); + double k4 = h * f(t + h, y + k3); + y += (k1 + 2 * k2 + 2 * k3 + k4) / 6; + } + + return points; + } + + [Example("MatrixSeries (chemical process simulation problem)")] + public static PlotModel MatrixSeriesWest0479() + { + // http://www.cise.ufl.edu/research/sparse/matrices/HB/west0479 + var model = new PlotModel(); + + double[,] matrix = null; + + + + using (var reader = new StreamReader(typeof(MiscExamples).GetTypeInfo().Assembly.GetManifestResourceStream("ExampleLibrary.Resources.west0479.mtx"))) + { + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + if (line.StartsWith("%")) + { + continue; + } + + var v = line.Split(' '); + if (matrix == null) + { + int m = int.Parse(v[0]); + int n = int.Parse(v[1]); + matrix = new double[m, n]; + continue; + } + + int i = int.Parse(v[0]) - 1; + int j = int.Parse(v[1]) - 1; + matrix[i, j] = double.Parse(v[2], CultureInfo.InvariantCulture); + } + } + + // Reverse the vertical axis + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Series.Add(new MatrixSeries { Matrix = matrix, ShowDiagonal = true }); + + return model; + } + + [Example("Train schedule")] + public static PlotModel TrainSchedule() + { + //// http://www.edwardtufte.com/tufte/books_vdqi + //// http://marlenacompton.com/?p=103 + //// http://mbostock.github.com/protovis/ex/caltrain.html + //// http://en.wikipedia.org/wiki/%C3%89tienne-Jules_Marey + //// http://mbostock.github.com/protovis/ex/marey-train-schedule.jpg + //// http://c82.net/posts.php?id=66 + + var model = new PlotModel + { + Title = "Train schedule", + Subtitle = "Bergensbanen (Oslo-Bergen, Norway)", + IsLegendVisible = false, + PlotAreaBorderColor = OxyColors.LightGray, + }; + + var distanceAxis = new LinearAxis + { + Position = AxisPosition.Left, + Minimum = -20, + Maximum = 540, + Title = "Distance from Oslo S", + IsAxisVisible = true, + StringFormat = "0", + }; + + model.Axes.Add(distanceAxis); + + var stationAxis = new CustomAxis + { + MajorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColors.LightGray, + Minimum = distanceAxis.Minimum, + Maximum = distanceAxis.Maximum, + Position = AxisPosition.Right, + IsPanEnabled = false, + IsZoomEnabled = false, + MajorTickSize = 0, + }; + + distanceAxis.AxisChanged += (sender, e) => + { + stationAxis.Minimum = distanceAxis.ActualMinimum; + stationAxis.Maximum = distanceAxis.ActualMaximum; + }; + + model.Axes.Add(stationAxis); + + model.Axes.Add( + new TimeSpanAxis + { + Position = AxisPosition.Bottom, + Minimum = 0, + Maximum = TimeSpanAxis.ToDouble(TimeSpan.FromHours(24)), + StringFormat = "hh", + Title = "Time", + MajorStep = TimeSpanAxis.ToDouble(TimeSpan.FromHours(1)), + MinorStep = TimeSpanAxis.ToDouble(TimeSpan.FromMinutes(10)), + TickStyle = TickStyle.None, + MajorGridlineStyle = LineStyle.Solid, + MajorGridlineColor = OxyColors.LightGray, + MinorGridlineStyle = LineStyle.Solid, + MinorGridlineColor = OxyColor.FromArgb(255, 240, 240, 240) + }); + + // Read the train schedule from a .csv resource + using (var reader = new StreamReader(GetResourceStream("Bergensbanen.csv"))) + { + string header = reader.ReadLine(); + var headerFields = header.Split(';'); + int lines = headerFields.Length - 3; + var stations = new LineSeries() + { + StrokeThickness = 0, + MarkerType = MarkerType.Circle, + MarkerFill = OxyColor.FromAColor(200, OxyColors.Black), + MarkerSize = 4, + }; + + // Add the line series for each train line + var series = new LineSeries[lines]; + for (int i = 0; i < series.Length; i++) + { + series[i] = new LineSeries + { + Title = headerFields[3 + i], + Color = + OxyColor.FromAColor( + 180, OxyColors.Black), + StrokeThickness = 2, + TrackerFormatString = + "Train {0}\nTime: {2}\nDistance from Oslo S: {4:0.0} km", + }; + model.Series.Add(series[i]); + } + + // Parse the train schedule + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + + // skip comments + if (line == null || line.StartsWith("//")) + { + continue; + } + + var fields = line.Split(';'); + double x = double.Parse(fields[1], CultureInfo.InvariantCulture); + if (!string.IsNullOrEmpty(fields[0])) + { + stationAxis.MajorTicks.Add(x); + stationAxis.Labels.Add(fields[0]); + } + + for (int i = 0; i < series.Length; i++) + { + if (string.IsNullOrEmpty(fields[i + 3])) + { + continue; + } + + // Convert time from hhmm to a time span + int hhmm = int.Parse(fields[i + 3]); + var span = new TimeSpan(0, hhmm / 100, (hhmm % 100), 0); + double t = TimeSpanAxis.ToDouble(span); + + // Add the point to the line + series[i].Points.Add(new DataPoint(t, x)); + + // Add the point for the station + stations.Points.Add(new DataPoint(t, x)); + } + } + + // add points and NaN (to make a line break) when passing midnight + double tmidnight = TimeSpanAxis.ToDouble(TimeSpan.FromHours(24)); + foreach (LineSeries s in model.Series) + { + for (int i = 0; i + 1 < s.Points.Count; i++) + { + if (Math.Abs(s.Points[i].X - s.Points[i + 1].X) > tmidnight / 2) + { + double x0 = s.Points[i].X; + if (x0 > tmidnight / 2) + { + x0 -= tmidnight; + } + + double x1 = s.Points[i + 1].X; + if (x1 > tmidnight / 2) + { + x1 -= tmidnight; + } + + double y = s.Points[i].Y + (s.Points[i + 1].Y - s.Points[i].Y) / (x1 - x0) * (0 - x0); + s.Points.Insert(i + 1, new DataPoint(x0 < x1 ? 0 : tmidnight, y)); + s.Points.Insert(i + 1, new DataPoint(double.NaN, y)); + s.Points.Insert(i + 1, new DataPoint(x0 < x1 ? tmidnight : 0, y)); + i += 3; + } + } + } + + model.Series.Add(stations); + } + + return model; + } + + [Example("La Linea (AreaSeries)")] + public static PlotModel LaLineaAreaSeries() + { + // http://en.wikipedia.org/wiki/La_Linea_(TV_series) + var model = new PlotModel + { + Title = "La Linea", + PlotType = PlotType.Cartesian, + Background = OxyColor.FromRgb(84, 98, 207) + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -500, Maximum = 1000 }); + var series1 = new AreaSeries { Fill = OxyColors.White, StrokeThickness = 0 }; + series1.Points.Append(GetLineaPoints()); + model.Series.Add(series1); + return model; + } + + [Example("La Linea (LineSeries)")] + public static PlotModel LaLinea() + { + // http://en.wikipedia.org/wiki/La_Linea_(TV_series) + var model = new PlotModel + { + Title = "La Linea", + PlotType = PlotType.Cartesian, + Background = OxyColor.FromRgb(84, 98, 207) + }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -500, Maximum = 1000 }); + var series1 = new LineSeries { Color = OxyColors.White, StrokeThickness = 1.5 }; + series1.Points.Append(GetLineaPoints()); + model.Series.Add(series1); + return model; + } + + /// + /// Appends the specified target. + /// + /// + /// The target. + /// The source. + public static void Append(this IList target, IEnumerable source) + { + foreach (var item in source) + { + target.Add(item); + } + } + + private static IEnumerable GetLineaPoints() + { + var points = new List(); + + // The original image was vectorized by http://www.autotracer.org/ + // Then inkscape was used to convert from svg to xaml http://inkscape.org/ + // The xaml geometry was imported by Geometry.Parse and converted to a polyline + // by Geometry.GetFlattenedPathGeometry(); + // The resulting points were output to the following code: + points.Add(new DataPoint(589.3649979, 16.10595703)); + points.Add(new DataPoint(437.9979935, 16.10595703)); + points.Add(new DataPoint(400.4249954, 16.10595703)); + points.Add(new DataPoint(399.1255264, 16.05047607)); + points.Add(new DataPoint(397.463356, 15.92333984)); + points.Add(new DataPoint(393.5852432, 15.69073486)); + points.Add(new DataPoint(389.8589859, 15.88067627)); + points.Add(new DataPoint(388.3866653, 16.28186035)); + points.Add(new DataPoint(387.3529739, 16.96594238)); + points.Add(new DataPoint(386.8373489, 18.53930664)); + points.Add(new DataPoint(387.2163773, 20.51794434)); + points.Add(new DataPoint(387.9814529, 22.51843262)); + points.Add(new DataPoint(388.6240005, 24.15698242)); + points.Add(new DataPoint(395.958992, 45.09094238)); + points.Add(new DataPoint(399.2686234, 54.89562988)); + points.Add(new DataPoint(402.1330338, 64.90338135)); + points.Add(new DataPoint(404.5822525, 75.06884766)); + points.Add(new DataPoint(406.6462479, 85.34680176)); + points.Add(new DataPoint(409.7385635, 106.0593262)); + points.Add(new DataPoint(411.6500015, 126.6789551)); + points.Add(new DataPoint(412.0961685, 137.0930786)); + points.Add(new DataPoint(412.0253677, 147.4713135)); + points.Add(new DataPoint(411.4655228, 157.8103638)); + points.Add(new DataPoint(410.4446182, 168.1069336)); + points.Add(new DataPoint(408.9906387, 178.3577881)); + points.Add(new DataPoint(407.1315689, 188.5595703)); + points.Add(new DataPoint(404.8953629, 198.7091064)); + points.Add(new DataPoint(402.3099747, 208.8029785)); + points.Add(new DataPoint(392.9860001, 237.2509766)); + points.Add(new DataPoint(392.1175613, 240.0527954)); + points.Add(new DataPoint(391.2060013, 243.0959473)); + points.Add(new DataPoint(390.5509415, 246.1691284)); + points.Add(new DataPoint(390.4520035, 249.0609741)); + points.Add(new DataPoint(391.406044, 252.6694336)); + points.Add(new DataPoint(393.1980057, 256.0982056)); + points.Add(new DataPoint(395.3566971, 259.3631287)); + points.Add(new DataPoint(397.4109879, 262.47995)); + points.Add(new DataPoint(411.7649918, 287.7079468)); + points.Add(new DataPoint(426.5997696, 312.9102173)); + points.Add(new DataPoint(441.8913651, 337.8200684)); + points.Add(new DataPoint(457.3402786, 362.6333923)); + points.Add(new DataPoint(472.6469803, 387.5459595)); + points.Add(new DataPoint(478.0007401, 395.7557983)); + points.Add(new DataPoint(483.6958694, 403.8400879)); + points.Add(new DataPoint(489.2894974, 411.9628296)); + points.Add(new DataPoint(494.3389969, 420.2879639)); + points.Add(new DataPoint(494.9800491, 421.8480225)); + points.Add(new DataPoint(495.4455032, 423.6903687)); + points.Add(new DataPoint(496.1577225, 427.7724609)); + points.Add(new DataPoint(497.0915604, 431.6355591)); + points.Add(new DataPoint(497.8341141, 433.2041321)); + points.Add(new DataPoint(498.8629837, 434.3809509)); + points.Add(new DataPoint(500.0935135, 434.9877625)); + points.Add(new DataPoint(501.7391434, 435.3059082)); + points.Add(new DataPoint(505.7623367, 435.3148193)); + points.Add(new DataPoint(509.9061356, 434.8848267)); + points.Add(new DataPoint(511.7024612, 434.6542969)); + points.Add(new DataPoint(513.1439896, 434.4929504)); + points.Add(new DataPoint(520.0768509, 434.1251831)); + points.Add(new DataPoint(527.3961258, 434.1952209)); + points.Add(new DataPoint(534.6892776, 434.728363)); + points.Add(new DataPoint(541.544014, 435.7499695)); + points.Add(new DataPoint(544.2357864, 436.3025513)); + points.Add(new DataPoint(547.021492, 437.0792236)); + points.Add(new DataPoint(549.6099319, 438.2590027)); + points.Add(new DataPoint(551.7099686, 440.0209656)); + points.Add(new DataPoint(552.7028275, 441.4446106)); + points.Add(new DataPoint(553.2691116, 442.791626)); + points.Add(new DataPoint(553.4498978, 444.0619202)); + points.Add(new DataPoint(553.2864456, 445.2554626)); + points.Add(new DataPoint(552.0910721, 447.4119873)); + points.Add(new DataPoint(550.0122147, 449.2607117)); + points.Add(new DataPoint(547.3790359, 450.8010864)); + points.Add(new DataPoint(544.5206985, 452.0325928)); + points.Add(new DataPoint(541.766304, 452.9547119)); + points.Add(new DataPoint(539.445015, 453.5669556)); + points.Add(new DataPoint(539.445015, 454.6409607)); + points.Add(new DataPoint(542.6554031, 455.4246521)); + points.Add(new DataPoint(546.0063553, 455.8735962)); + points.Add(new DataPoint(549.2799149, 456.4869385)); + points.Add(new DataPoint(552.2580032, 457.7639465)); + points.Add(new DataPoint(554.3335648, 459.5966797)); + points.Add(new DataPoint(555.6600418, 461.8208313)); + points.Add(new DataPoint(556.278389, 464.282959)); + points.Add(new DataPoint(556.2294998, 466.8295898)); + points.Add(new DataPoint(555.55439, 469.307251)); + points.Add(new DataPoint(554.2939529, 471.5625)); + points.Add(new DataPoint(552.4892044, 473.4418945)); + points.Add(new DataPoint(550.1809769, 474.7919617)); + points.Add(new DataPoint(547.1414261, 475.8059387)); + points.Add(new DataPoint(543.8482132, 476.5288391)); + points.Add(new DataPoint(537.2979813, 477.0559692)); + points.Add(new DataPoint(535.5239944, 476.8666077)); + points.Add(new DataPoint(533.5114822, 476.5535889)); + points.Add(new DataPoint(531.5334549, 476.4162598)); + points.Add(new DataPoint(529.8629837, 476.7539673)); + points.Add(new DataPoint(529.0471268, 477.3421631)); + points.Add(new DataPoint(528.5394363, 478.1289673)); + points.Add(new DataPoint(528.1448441, 480.0927124)); + points.Add(new DataPoint(528.071846, 482.2338257)); + points.Add(new DataPoint(527.7129593, 484.1409607)); + points.Add(new DataPoint(526.901741, 485.4877014)); + points.Add(new DataPoint(525.8139114, 486.4950867)); + points.Add(new DataPoint(523.0528641, 487.6643372)); + points.Add(new DataPoint(519.9188919, 487.9933777)); + points.Add(new DataPoint(516.9010086, 487.8269653)); + points.Add(new DataPoint(511.7325516, 486.9451599)); + points.Add(new DataPoint(506.4563065, 485.4539185)); + points.Add(new DataPoint(501.155159, 483.4500427)); + points.Add(new DataPoint(495.912117, 481.0302124)); + points.Add(new DataPoint(485.9321365, 475.3295898)); + points.Add(new DataPoint(481.3610916, 472.2423096)); + points.Add(new DataPoint(477.1800003, 469.125946)); + points.Add(new DataPoint(465.3709793, 459.3179626)); + points.Add(new DataPoint(464.3509598, 458.3116455)); + points.Add(new DataPoint(463.1867142, 457.1624451)); + points.Add(new DataPoint(461.9141312, 456.2180176)); + points.Add(new DataPoint(460.5689774, 455.8259583)); + points.Add(new DataPoint(459.6923904, 456.0762939)); + points.Add(new DataPoint(458.8656693, 456.7503662)); + points.Add(new DataPoint(457.3631058, 458.907959)); + points.Add(new DataPoint(456.063179, 461.3753052)); + points.Add(new DataPoint(455.4898758, 462.436554)); + points.Add(new DataPoint(454.9679642, 463.2289734)); + points.Add(new DataPoint(453.0795364, 465.3183289)); + points.Add(new DataPoint(450.8528519, 467.2734985)); + points.Add(new DataPoint(448.3575516, 468.9848328)); + points.Add(new DataPoint(445.6630936, 470.3425903)); + points.Add(new DataPoint(442.83918, 471.2370605)); + points.Add(new DataPoint(439.9552689, 471.5585938)); + points.Add(new DataPoint(437.0810318, 471.1974487)); + points.Add(new DataPoint(434.2859879, 470.0439453)); + points.Add(new DataPoint(432.4744034, 468.6621399)); + points.Add(new DataPoint(431.3244705, 467.0726013)); + points.Add(new DataPoint(430.7551956, 465.3302612)); + points.Add(new DataPoint(430.6856155, 463.4900818)); + points.Add(new DataPoint(431.0347672, 461.6070251)); + points.Add(new DataPoint(431.7216873, 459.7360229)); + points.Add(new DataPoint(433.7849808, 456.2499695)); + points.Add(new DataPoint(438.1093216, 450.118988)); + points.Add(new DataPoint(441.4749832, 444.3893433)); + points.Add(new DataPoint(444.0351639, 438.28302)); + points.Add(new DataPoint(445.0610428, 434.845459)); + points.Add(new DataPoint(445.9430008, 431.0219727)); + points.Add(new DataPoint(446.6270218, 428.7687378)); + points.Add(new DataPoint(447.4476395, 426.4767151)); + points.Add(new DataPoint(447.9032059, 424.1760559)); + points.Add(new DataPoint(447.492012, 421.8969727)); + points.Add(new DataPoint(445.6156082, 418.2295837)); + points.Add(new DataPoint(443.3608475, 414.6139832)); + points.Add(new DataPoint(438.1008682, 407.5364685)); + points.Add(new DataPoint(432.48069, 400.6614685)); + points.Add(new DataPoint(427.2689896, 393.9859619)); + points.Add(new DataPoint(389.1699905, 339.2359619)); + points.Add(new DataPoint(374.5550003, 318.3009644)); + points.Add(new DataPoint(372.5515823, 314.8404541)); + points.Add(new DataPoint(370.2787552, 310.9485779)); + points.Add(new DataPoint(367.7467728, 307.2946777)); + points.Add(new DataPoint(366.3868484, 305.7660828)); + points.Add(new DataPoint(364.9659805, 304.5479736)); + points.Add(new DataPoint(363.9477615, 304.0406799)); + points.Add(new DataPoint(363.082222, 304.0159912)); + points.Add(new DataPoint(361.6236038, 304.9024658)); + points.Add(new DataPoint(360.2191849, 306.1834412)); + points.Add(new DataPoint(359.4213638, 306.651886)); + points.Add(new DataPoint(358.4979935, 306.8349609)); + points.Add(new DataPoint(356.6694107, 306.4464722)); + points.Add(new DataPoint(354.9371109, 305.5308228)); + points.Add(new DataPoint(353.2544937, 304.4515076)); + points.Add(new DataPoint(351.5749893, 303.5719604)); + points.Add(new DataPoint(343.4895706, 301.1234131)); + points.Add(new DataPoint(335.0169449, 299.8048401)); + points.Add(new DataPoint(326.3076553, 299.5128174)); + points.Add(new DataPoint(317.5122147, 300.1439514)); + points.Add(new DataPoint(308.7811966, 301.5948486)); + points.Add(new DataPoint(300.2651443, 303.762085)); + points.Add(new DataPoint(292.1145401, 306.5422668)); + points.Add(new DataPoint(284.4799881, 309.8319702)); + points.Add(new DataPoint(282.3371964, 310.7483521)); + points.Add(new DataPoint(279.925972, 311.644928)); + points.Add(new DataPoint(274.7942581, 313.5763245)); + points.Add(new DataPoint(270.0769119, 316.0212708)); + points.Add(new DataPoint(268.1836319, 317.559845)); + points.Add(new DataPoint(266.7659988, 319.3749695)); + points.Add(new DataPoint(271.6227798, 320.1968384)); + points.Add(new DataPoint(276.5877457, 321.7830811)); + points.Add(new DataPoint(281.472847, 323.7190247)); + points.Add(new DataPoint(286.090004, 325.5899658)); + points.Add(new DataPoint(298.3649979, 330.7419739)); + points.Add(new DataPoint(310.3880997, 336.8226929)); + points.Add(new DataPoint(321.8024063, 343.941803)); + points.Add(new DataPoint(332.2509842, 352.2089539)); + points.Add(new DataPoint(339.2033768, 358.533844)); + points.Add(new DataPoint(342.4841385, 361.901825)); + points.Add(new DataPoint(345.4439774, 365.5359497)); + points.Add(new DataPoint(346.445076, 367.0002136)); + points.Add(new DataPoint(347.3386307, 368.7592163)); + points.Add(new DataPoint(347.6443558, 370.5680847)); + points.Add(new DataPoint(347.4267044, 371.4147034)); + points.Add(new DataPoint(346.8819962, 372.1819458)); + points.Add(new DataPoint(345.387001, 372.7861023)); + points.Add(new DataPoint(343.5981216, 372.4627075)); + points.Add(new DataPoint(341.8064041, 371.7001953)); + points.Add(new DataPoint(340.3029861, 370.986969)); + points.Add(new DataPoint(336.1688919, 369.4472046)); + points.Add(new DataPoint(331.5998611, 368.1002197)); + points.Add(new DataPoint(326.9541702, 367.1023254)); + points.Add(new DataPoint(322.5899734, 366.6099548)); + points.Add(new DataPoint(324.6785049, 369.6851501)); + points.Add(new DataPoint(327.4601212, 372.3129578)); + points.Add(new DataPoint(330.467659, 374.7735291)); + points.Add(new DataPoint(333.2339859, 377.3469543)); + points.Add(new DataPoint(338.3369217, 383.6273193)); + points.Add(new DataPoint(342.70298, 390.7063293)); + points.Add(new DataPoint(344.4534683, 394.4726563)); + points.Add(new DataPoint(345.8323135, 398.3514099)); + points.Add(new DataPoint(346.7769547, 402.3135376)); + points.Add(new DataPoint(347.2249832, 406.3299561)); + points.Add(new DataPoint(346.8078384, 412.0097046)); + points.Add(new DataPoint(345.1297989, 416.5983276)); + points.Add(new DataPoint(342.383522, 420.1838074)); + points.Add(new DataPoint(338.7616043, 422.8540955)); + points.Add(new DataPoint(334.4566727, 424.6971741)); + points.Add(new DataPoint(329.6613541, 425.8010559)); + points.Add(new DataPoint(324.5682449, 426.2536621)); + points.Add(new DataPoint(319.3700027, 426.1429749)); + points.Add(new DataPoint(315.144783, 425.6447144)); + points.Add(new DataPoint(311.0141983, 424.7691345)); + points.Add(new DataPoint(303.0388565, 422.0056763)); + points.Add(new DataPoint(295.4478226, 418.0917969)); + points.Add(new DataPoint(288.2450027, 413.2668457)); + points.Add(new DataPoint(281.4342422, 407.769989)); + points.Add(new DataPoint(275.0194168, 401.8405762)); + points.Add(new DataPoint(269.0043716, 395.717804)); + points.Add(new DataPoint(263.393013, 389.6409607)); + points.Add(new DataPoint(255.0782547, 379.5436707)); + points.Add(new DataPoint(247.6409988, 368.3999634)); + points.Add(new DataPoint(244.4098587, 362.5210571)); + points.Add(new DataPoint(241.5882645, 356.4829712)); + points.Add(new DataPoint(239.2395096, 350.3198853)); + points.Add(new DataPoint(237.4270096, 344.0659485)); + points.Add(new DataPoint(236.2694168, 338.2407532)); + points.Add(new DataPoint(235.5486526, 332.3677368)); + points.Add(new DataPoint(235.0773697, 320.528717)); + points.Add(new DataPoint(235.3326797, 308.6495667)); + points.Add(new DataPoint(235.6340103, 296.8309631)); + points.Add(new DataPoint(233.1889725, 297.9562988)); + points.Add(new DataPoint(230.9140091, 299.4570923)); + points.Add(new DataPoint(226.5090103, 302.6929626)); + points.Add(new DataPoint(206.6489944, 315.875946)); + points.Add(new DataPoint(157.2670059, 346.7819519)); + points.Add(new DataPoint(136.8219986, 360.059967)); + points.Add(new DataPoint(132.2092514, 363.0340881)); + points.Add(new DataPoint(130.0033798, 364.6920166)); + points.Add(new DataPoint(128.1559982, 366.6599731)); + points.Add(new DataPoint(127.0190811, 368.5368958)); + points.Add(new DataPoint(126.298027, 370.4631348)); + points.Add(new DataPoint(125.9532547, 372.4280701)); + points.Add(new DataPoint(125.9451218, 374.4211121)); + points.Add(new DataPoint(126.7804031, 378.4490356)); + points.Add(new DataPoint(128.4870071, 382.4620972)); + points.Add(new DataPoint(130.748024, 386.3754272)); + points.Add(new DataPoint(133.2466202, 390.104248)); + points.Add(new DataPoint(135.6659012, 393.5636902)); + points.Add(new DataPoint(137.689003, 396.6689453)); + points.Add(new DataPoint(139.2043839, 400.197052)); + points.Add(new DataPoint(139.5524673, 402.0329285)); + points.Add(new DataPoint(139.5626297, 403.8374634)); + points.Add(new DataPoint(139.1861954, 405.551239)); + points.Add(new DataPoint(138.3745499, 407.1148682)); + points.Add(new DataPoint(137.0790329, 408.4689026)); + points.Add(new DataPoint(135.2509995, 409.5539551)); + points.Add(new DataPoint(132.8812943, 410.31427)); + points.Add(new DataPoint(130.5507584, 410.5262146)); + points.Add(new DataPoint(128.270546, 410.2424316)); + points.Add(new DataPoint(126.0518265, 409.5155334)); + points.Add(new DataPoint(123.9057388, 408.3982239)); + points.Add(new DataPoint(121.8434372, 406.9431458)); + points.Add(new DataPoint(118.0148697, 403.2301941)); + points.Add(new DataPoint(114.6553879, 398.7979126)); + points.Add(new DataPoint(111.8542252, 394.0675049)); + points.Add(new DataPoint(109.7006912, 389.4601135)); + points.Add(new DataPoint(108.2840042, 385.3969727)); + points.Add(new DataPoint(107.7778549, 382.5092468)); + points.Add(new DataPoint(107.3788681, 379.2887268)); + points.Add(new DataPoint(106.6309433, 376.2470703)); + points.Add(new DataPoint(105.0779953, 373.8959656)); + points.Add(new DataPoint(103.1701126, 372.6677246)); + points.Add(new DataPoint(100.7825394, 371.7599487)); + points.Add(new DataPoint(95.13137054, 370.6252136)); + points.Add(new DataPoint(89.25051117, 369.9303284)); + points.Add(new DataPoint(86.57584381, 369.5724182)); + points.Add(new DataPoint(84.26599884, 369.1139526)); + points.Add(new DataPoint(78.20024872, 367.3027649)); + points.Add(new DataPoint(71.70685577, 364.820343)); + points.Add(new DataPoint(65.1133194, 361.6892395)); + points.Add(new DataPoint(58.74712372, 357.9318237)); + points.Add(new DataPoint(52.93579102, 353.5706482)); + points.Add(new DataPoint(48.00682831, 348.6281433)); + points.Add(new DataPoint(45.97557068, 345.9458923)); + points.Add(new DataPoint(44.28772736, 343.1267395)); + points.Add(new DataPoint(42.98422241, 340.1734924)); + points.Add(new DataPoint(42.10599518, 337.0889587)); + points.Add(new DataPoint(41.90753937, 335.2592163)); + points.Add(new DataPoint(42.08698273, 333.7605286)); + points.Add(new DataPoint(43.18836975, 331.3730774)); + points.Add(new DataPoint(44.62782288, 329.1598206)); + points.Add(new DataPoint(45.6230011, 326.3539734)); + points.Add(new DataPoint(45.62973022, 324.9945984)); + points.Add(new DataPoint(45.33054352, 323.6192627)); + points.Add(new DataPoint(44.36862183, 320.8330994)); + points.Add(new DataPoint(43.98298645, 319.4284058)); + points.Add(new DataPoint(43.84563446, 318.0201111)); + points.Add(new DataPoint(44.09512329, 316.6112671)); + points.Add(new DataPoint(44.86999512, 315.2049561)); + points.Add(new DataPoint(45.80908966, 314.2088623)); + points.Add(new DataPoint(46.79941559, 313.5540161)); + points.Add(new DataPoint(48.9025116, 313.1113892)); + points.Add(new DataPoint(51.11682129, 313.5637512)); + points.Add(new DataPoint(53.37987518, 314.5978394)); + points.Add(new DataPoint(57.8022995, 317.1580811)); + points.Add(new DataPoint(59.83672333, 318.0577087)); + points.Add(new DataPoint(61.6700058, 318.2859497)); + points.Add(new DataPoint(62.82819366, 317.6254883)); + points.Add(new DataPoint(63.23600006, 316.3283386)); + points.Add(new DataPoint(63.24330902, 314.8067627)); + points.Add(new DataPoint(63.20000458, 313.4729614)); + points.Add(new DataPoint(63.68109894, 310.3050232)); + points.Add(new DataPoint(64.93375397, 307.6513367)); + points.Add(new DataPoint(67.09728241, 305.979187)); + points.Add(new DataPoint(68.56415558, 305.6572571)); + points.Add(new DataPoint(70.31099701, 305.7559509)); + points.Add(new DataPoint(73.2078476, 306.4935913)); + points.Add(new DataPoint(76.04866791, 307.6478271)); + points.Add(new DataPoint(81.46486664, 310.9243164)); + points.Add(new DataPoint(86.36489105, 315.0218811)); + points.Add(new DataPoint(90.55399323, 319.3769531)); + points.Add(new DataPoint(92.14154816, 321.4163208)); + points.Add(new DataPoint(93.72263336, 323.6399536)); + points.Add(new DataPoint(95.39614105, 325.7593689)); + points.Add(new DataPoint(97.26099396, 327.4859619)); + points.Add(new DataPoint(98.87421417, 328.2453918)); + points.Add(new DataPoint(100.5960007, 328.4575806)); + points.Add(new DataPoint(104.1259995, 328.1189575)); + points.Add(new DataPoint(107.9671097, 328.0540771)); + points.Add(new DataPoint(112.0256271, 328.345459)); + points.Add(new DataPoint(116.0258255, 328.4305725)); + points.Add(new DataPoint(119.6919937, 327.7469482)); + points.Add(new DataPoint(122.6980515, 326.2321777)); + points.Add(new DataPoint(125.5723801, 324.1764526)); + points.Add(new DataPoint(128.3242722, 321.9129944)); + points.Add(new DataPoint(130.9630051, 319.7749634)); + points.Add(new DataPoint(158.6139908, 297.5969543)); + points.Add(new DataPoint(183.9269943, 278.8919678)); + points.Add(new DataPoint(215.7729874, 251.3609619)); + points.Add(new DataPoint(222.6591263, 245.7957153)); + points.Add(new DataPoint(229.6908646, 240.2703247)); + points.Add(new DataPoint(236.5836563, 234.5932617)); + points.Add(new DataPoint(243.0529861, 228.572937)); + points.Add(new DataPoint(246.137764, 224.8230591)); + points.Add(new DataPoint(248.7661209, 220.4605103)); + points.Add(new DataPoint(251.0138321, 215.6484985)); + points.Add(new DataPoint(252.9567337, 210.5499878)); + points.Add(new DataPoint(256.2312393, 200.1459351)); + points.Add(new DataPoint(257.7144547, 195.1665039)); + points.Add(new DataPoint(259.1959915, 190.5529785)); + points.Add(new DataPoint(263.9845047, 175.0708008)); + points.Add(new DataPoint(267.8167191, 159.2056274)); + points.Add(new DataPoint(270.6394424, 143.0612183)); + points.Add(new DataPoint(272.3993607, 126.7412109)); + points.Add(new DataPoint(273.043251, 110.3493042)); + points.Add(new DataPoint(272.5178299, 93.98913574)); + points.Add(new DataPoint(270.7698441, 77.76446533)); + points.Add(new DataPoint(267.7460098, 61.77893066)); + points.Add(new DataPoint(260.9010086, 28.45196533)); + points.Add(new DataPoint(260.3377457, 25.5088501)); + points.Add(new DataPoint(259.7099991, 22.24182129)); + points.Add(new DataPoint(258.5879898, 19.265625)); + points.Add(new DataPoint(257.7073746, 18.07867432)); + points.Add(new DataPoint(256.5419998, 17.19494629)); + points.Add(new DataPoint(254.5226212, 16.44396973)); + points.Add(new DataPoint(252.1078568, 16.0401001)); + points.Add(new DataPoint(246.5816116, 15.96911621)); + points.Add(new DataPoint(240.9423294, 16.37298584)); + points.Add(new DataPoint(238.3862076, 16.56274414)); + points.Add(new DataPoint(236.1689835, 16.64294434)); + points.Add(new DataPoint(185.1770096, 17.17895508)); + points.Add(new DataPoint(0, 16.64294434)); + points.Add(new DataPoint(0, 0.53894043)); + points.Add(new DataPoint(188.9400101, 0.53894043)); + points.Add(new DataPoint(242.0799942, 0.53894043)); + points.Add(new DataPoint(244.6571732, 0.474975586)); + points.Add(new DataPoint(247.5546951, 0.33001709)); + points.Add(new DataPoint(253.8458633, 0.078552246)); + points.Add(new DataPoint(260.0235977, 0.347839355)); + points.Add(new DataPoint(262.779335, 0.853759766)); + points.Add(new DataPoint(265.1579971, 1.70098877)); + points.Add(new DataPoint(266.7366104, 2.746398926)); + points.Add(new DataPoint(268.0821915, 4.172119141)); + points.Add(new DataPoint(270.1900101, 7.797119141)); + points.Add(new DataPoint(271.7128067, 11.84075928)); + points.Add(new DataPoint(272.8819962, 15.56799316)); + points.Add(new DataPoint(276.034523, 25.44775391)); + points.Add(new DataPoint(279.0441055, 35.50836182)); + points.Add(new DataPoint(281.6616287, 45.66326904)); + points.Add(new DataPoint(283.6380081, 55.82598877)); + points.Add(new DataPoint(285.7761917, 72.32995605)); + points.Add(new DataPoint(287.0616837, 88.9072876)); + points.Add(new DataPoint(287.4597855, 105.5118408)); + points.Add(new DataPoint(286.9358597, 122.0977173)); + points.Add(new DataPoint(285.4552994, 138.6187744)); + points.Add(new DataPoint(282.9833755, 155.0289917)); + points.Add(new DataPoint(279.4855118, 171.2824097)); + points.Add(new DataPoint(274.9270096, 187.3329468)); + points.Add(new DataPoint(271.4097672, 198.2474976)); + points.Add(new DataPoint(267.3623734, 209.4165039)); + points.Add(new DataPoint(262.4050369, 220.1444092)); + points.Add(new DataPoint(259.4664688, 225.1257324)); + points.Add(new DataPoint(256.1579971, 229.7359619)); + points.Add(new DataPoint(249.3205032, 237.2365723)); + points.Add(new DataPoint(241.720253, 244.1188354)); + points.Add(new DataPoint(233.794136, 250.6709595)); + points.Add(new DataPoint(225.9790115, 257.1809692)); + points.Add(new DataPoint(195.5280228, 282.9415894)); + points.Add(new DataPoint(164.2490005, 307.6559448)); + points.Add(new DataPoint(141.1689987, 324.8109741)); + points.Add(new DataPoint(133.2555008, 330.7440796)); + points.Add(new DataPoint(129.0609055, 333.3323975)); + points.Add(new DataPoint(124.5289993, 335.2859497)); + points.Add(new DataPoint(122.1544113, 335.8482361)); + points.Add(new DataPoint(119.7157364, 336.0837402)); + points.Add(new DataPoint(114.7126236, 335.969696)); + points.Add(new DataPoint(109.6527023, 335.7345581)); + points.Add(new DataPoint(104.6689987, 336.1689453)); + points.Add(new DataPoint(102.779686, 336.7739563)); + points.Add(new DataPoint(100.6949997, 337.5380859)); + points.Add(new DataPoint(98.61257172, 337.9761353)); + points.Add(new DataPoint(96.73000336, 337.6029663)); + points.Add(new DataPoint(94.59128571, 335.8127136)); + points.Add(new DataPoint(92.66425323, 333.2740784)); + points.Add(new DataPoint(90.92359161, 330.5338745)); + points.Add(new DataPoint(89.34400177, 328.1389465)); + points.Add(new DataPoint(87.08150482, 325.4346313)); + points.Add(new DataPoint(84.48600006, 322.8813171)); + points.Add(new DataPoint(78.90499115, 318.3849487)); + points.Add(new DataPoint(77.3181076, 317.091217)); + points.Add(new DataPoint(75.22336578, 315.5139465)); + points.Add(new DataPoint(73.02420807, 314.5059509)); + points.Add(new DataPoint(72.01151276, 314.4819031)); + points.Add(new DataPoint(71.12400055, 314.9199524)); + points.Add(new DataPoint(70.59803009, 315.7275085)); + points.Add(new DataPoint(70.51831818, 316.7388916)); + points.Add(new DataPoint(71.29537201, 319.0906982)); + points.Add(new DataPoint(72.65048981, 321.4106445)); + points.Add(new DataPoint(73.77899933, 323.1339722)); + points.Add(new DataPoint(77.82125092, 329.0054626)); + points.Add(new DataPoint(80.16477203, 331.7309265)); + points.Add(new DataPoint(82.71099091, 334.177948)); + points.Add(new DataPoint(84.92420197, 335.9799805)); + points.Add(new DataPoint(87.10187531, 337.9599609)); + points.Add(new DataPoint(88.68236542, 340.2526855)); + points.Add(new DataPoint(89.07314301, 341.5584412)); + points.Add(new DataPoint(89.10399628, 342.9929504)); + points.Add(new DataPoint(89.61742401, 343.8485413)); + points.Add(new DataPoint(89.34513092, 344.4684448)); + points.Add(new DataPoint(88.5472641, 344.7538757)); + points.Add(new DataPoint(87.48400116, 344.605957)); + points.Add(new DataPoint(85.91378021, 343.8370972)); + points.Add(new DataPoint(84.39550018, 342.7818298)); + points.Add(new DataPoint(81.58899689, 340.4889526)); + points.Add(new DataPoint(78.80124664, 338.1679382)); + points.Add(new DataPoint(75.64672089, 335.4441223)); + points.Add(new DataPoint(68.57024384, 329.6803589)); + points.Add(new DataPoint(64.81476593, 327.0864868)); + points.Add(new DataPoint(61.02541351, 324.9821167)); + points.Add(new DataPoint(57.28540802, 323.5902405)); + points.Add(new DataPoint(53.6780014, 323.1339722)); + points.Add(new DataPoint(55.6113739, 326.1587524)); + points.Add(new DataPoint(58.03131866, 328.9006653)); + points.Add(new DataPoint(63.8632431, 333.7370911)); + points.Add(new DataPoint(70.23856354, 338.0457153)); + points.Add(new DataPoint(76.22199249, 342.2289734)); + points.Add(new DataPoint(77.03455353, 342.7995605)); + points.Add(new DataPoint(78.11525726, 343.5061951)); + points.Add(new DataPoint(80.57563019, 345.232605)); + points.Add(new DataPoint(82.59217072, 347.217926)); + points.Add(new DataPoint(83.11811066, 348.24823)); + points.Add(new DataPoint(83.15399933, 349.2719727)); + points.Add(new DataPoint(82.68766022, 350.0397949)); + points.Add(new DataPoint(81.87210846, 350.3486328)); + points.Add(new DataPoint(79.6248703, 349.9825745)); + points.Add(new DataPoint(77.27544403, 348.9604797)); + points.Add(new DataPoint(76.33216095, 348.4492188)); + points.Add(new DataPoint(75.68700409, 348.0689697)); + points.Add(new DataPoint(66.5876236, 342.1790771)); + points.Add(new DataPoint(61.90306854, 339.4937744)); + points.Add(new DataPoint(56.897995, 337.35495)); + points.Add(new DataPoint(55.17505646, 336.726532)); + points.Add(new DataPoint(53.01000214, 336.1444702)); + points.Add(new DataPoint(51.04743958, 336.2538757)); + points.Add(new DataPoint(50.34353638, 336.7695007)); + points.Add(new DataPoint(49.93199921, 337.6999512)); + points.Add(new DataPoint(50.0814743, 339.3566589)); + points.Add(new DataPoint(51.06142426, 341.0038757)); + points.Add(new DataPoint(52.65550232, 342.6039124)); + points.Add(new DataPoint(54.64737701, 344.1190796)); + points.Add(new DataPoint(58.95914459, 346.743988)); + points.Add(new DataPoint(60.84635162, 347.7783203)); + points.Add(new DataPoint(62.26599884, 348.5769653)); + points.Add(new DataPoint(70.1079483, 352.9052734)); + points.Add(new DataPoint(78.1873703, 356.6586914)); + points.Add(new DataPoint(86.4916153, 359.8837585)); + points.Add(new DataPoint(95.00800323, 362.6269531)); + points.Add(new DataPoint(96.84983063, 363.0866394)); + points.Add(new DataPoint(98.97579193, 363.5275574)); + points.Add(new DataPoint(103.6091232, 364.5426941)); + points.Add(new DataPoint(107.965889, 366.0517273)); + points.Add(new DataPoint(109.7461472, 367.1099854)); + points.Add(new DataPoint(111.1039963, 368.43396)); + points.Add(new DataPoint(112.0068741, 370.5414429)); + points.Add(new DataPoint(112.4139938, 373.21521)); + points.Add(new DataPoint(112.6441269, 375.9950867)); + points.Add(new DataPoint(113.0159988, 378.4209595)); + points.Add(new DataPoint(113.902565, 381.2496643)); + points.Add(new DataPoint(115.2284775, 384.6081543)); + points.Add(new DataPoint(116.9393082, 388.2300415)); + points.Add(new DataPoint(118.980629, 391.8488464)); + points.Add(new DataPoint(121.2979813, 395.1981506)); + points.Add(new DataPoint(123.8369522, 398.0115662)); + points.Add(new DataPoint(126.5430984, 400.022644)); + points.Add(new DataPoint(129.3619919, 400.9649658)); + points.Add(new DataPoint(128.5566483, 397.5397949)); + points.Add(new DataPoint(126.8852463, 394.5133362)); + points.Add(new DataPoint(124.8594742, 391.6261902)); + points.Add(new DataPoint(122.9910049, 388.6189575)); + points.Add(new DataPoint(120.504631, 382.5281982)); + points.Add(new DataPoint(119.1972427, 376.1178589)); + points.Add(new DataPoint(119.0547104, 372.875061)); + points.Add(new DataPoint(119.2897568, 369.6510315)); + points.Add(new DataPoint(119.9299698, 366.4787292)); + points.Add(new DataPoint(121.0029984, 363.3909607)); + points.Add(new DataPoint(122.9761124, 359.8041687)); + points.Add(new DataPoint(125.5510788, 356.6000061)); + points.Add(new DataPoint(128.5915298, 353.7098083)); + points.Add(new DataPoint(131.9611282, 351.0648499)); + points.Add(new DataPoint(139.1423569, 346.2359619)); + points.Add(new DataPoint(146.0040054, 341.5639648)); + points.Add(new DataPoint(153.3126602, 336.4172363)); + points.Add(new DataPoint(160.8510056, 331.6148376)); + points.Add(new DataPoint(176.060997, 322.2139587)); + points.Add(new DataPoint(223.2120132, 292.0619507)); + points.Add(new DataPoint(241.0090103, 281.0089722)); + points.Add(new DataPoint(244.4554214, 278.2832642)); + points.Add(new DataPoint(248.0213699, 275.5827026)); + points.Add(new DataPoint(251.8383865, 273.5125122)); + points.Add(new DataPoint(253.8821487, 272.9029541)); + points.Add(new DataPoint(256.038002, 272.677948)); + points.Add(new DataPoint(255.5765762, 275.73526)); + points.Add(new DataPoint(254.4421158, 278.3285828)); + points.Add(new DataPoint(252.9171219, 280.7803345)); + points.Add(new DataPoint(251.2840042, 283.4129639)); + points.Add(new DataPoint(249.1513138, 287.4288635)); + points.Add(new DataPoint(247.2273636, 291.7029724)); + points.Add(new DataPoint(245.725502, 296.1263123)); + points.Add(new DataPoint(244.8589859, 300.5899658)); + points.Add(new DataPoint(244.4298477, 307.2876587)); + points.Add(new DataPoint(244.5635757, 313.9535828)); + points.Add(new DataPoint(245.2291336, 320.570282)); + points.Add(new DataPoint(246.3955154, 327.1204224)); + points.Add(new DataPoint(248.0315933, 333.5866089)); + points.Add(new DataPoint(250.1063919, 339.951416)); + points.Add(new DataPoint(252.5888138, 346.1975098)); + points.Add(new DataPoint(255.4478531, 352.3074646)); + points.Add(new DataPoint(262.1715469, 364.0494385)); + points.Add(new DataPoint(270.0290298, 375.0382385)); + points.Add(new DataPoint(278.7719803, 385.1347656)); + points.Add(new DataPoint(288.1519852, 394.1999512)); + points.Add(new DataPoint(294.92173, 399.6752014)); + points.Add(new DataPoint(302.1428604, 404.5257263)); + points.Add(new DataPoint(309.7718277, 408.7135925)); + points.Add(new DataPoint(317.7649918, 412.2009583)); + points.Add(new DataPoint(322.0982132, 413.5901184)); + points.Add(new DataPoint(326.4935989, 414.2129517)); + points.Add(new DataPoint(328.6687698, 414.1019592)); + points.Add(new DataPoint(330.8044205, 413.6372986)); + points.Add(new DataPoint(332.8823013, 412.7649841)); + points.Add(new DataPoint(334.8839798, 411.4309692)); + points.Add(new DataPoint(336.700325, 409.4726868)); + points.Add(new DataPoint(337.756813, 407.2593689)); + points.Add(new DataPoint(338.1652908, 404.8675537)); + points.Add(new DataPoint(338.0374832, 402.3738403)); + points.Add(new DataPoint(337.4851761, 399.8547668)); + points.Add(new DataPoint(336.6201553, 397.3868713)); + points.Add(new DataPoint(334.3989944, 392.9109497)); + points.Add(new DataPoint(331.2719803, 388.0760193)); + points.Add(new DataPoint(327.7468643, 383.5949097)); + points.Add(new DataPoint(319.7087479, 375.5498352)); + points.Add(new DataPoint(310.6974869, 368.4870605)); + points.Add(new DataPoint(301.1259842, 362.1179504)); + points.Add(new DataPoint(289.341011, 355.3789673)); + points.Add(new DataPoint(288.3749161, 354.5166321)); + points.Add(new DataPoint(287.4871292, 353.3829651)); + points.Add(new DataPoint(287.1665115, 352.1690369)); + points.Add(new DataPoint(287.3716812, 351.5917053)); + points.Add(new DataPoint(287.9019852, 351.0659485)); + points.Add(new DataPoint(290.0786819, 350.5000305)); + points.Add(new DataPoint(292.8593826, 350.8098145)); + points.Add(new DataPoint(295.6623917, 351.5259399)); + points.Add(new DataPoint(297.9060135, 352.1789551)); + points.Add(new DataPoint(300.6676102, 353.0059814)); + points.Add(new DataPoint(303.7700882, 354.0613708)); + points.Add(new DataPoint(310.5398636, 356.3453369)); + points.Add(new DataPoint(313.9782486, 357.3178101)); + points.Add(new DataPoint(317.2997208, 358.0065918)); + points.Add(new DataPoint(320.3897781, 358.2836609)); + points.Add(new DataPoint(323.1339798, 358.0209656)); + points.Add(new DataPoint(311.4509048, 349.4853516)); + points.Add(new DataPoint(299.2507401, 341.6953125)); + points.Add(new DataPoint(286.5124283, 334.8171387)); + points.Add(new DataPoint(273.215004, 329.0169678)); + points.Add(new DataPoint(258.7229996, 323.8179626)); + points.Add(new DataPoint(257.2878494, 323.337738)); + points.Add(new DataPoint(255.7744827, 322.6670837)); + points.Add(new DataPoint(254.4943924, 321.7168884)); + points.Add(new DataPoint(253.7590103, 320.3979492)); + points.Add(new DataPoint(253.827034, 319.0723267)); + points.Add(new DataPoint(254.5322647, 317.7234802)); + points.Add(new DataPoint(255.711647, 316.3885193)); + points.Add(new DataPoint(257.2022476, 315.1045837)); + points.Add(new DataPoint(260.465126, 312.8383789)); + points.Add(new DataPoint(261.9114456, 311.9303589)); + points.Add(new DataPoint(263.0170059, 311.2219543)); + points.Add(new DataPoint(271.8112259, 305.8678284)); + points.Add(new DataPoint(281.198616, 301.1617126)); + points.Add(new DataPoint(290.8884659, 297.0829773)); + points.Add(new DataPoint(300.590004, 293.6109619)); + points.Add(new DataPoint(310.0823746, 291.1308289)); + points.Add(new DataPoint(319.4608536, 289.9150696)); + points.Add(new DataPoint(328.9314041, 289.7652893)); + points.Add(new DataPoint(338.6999893, 290.4829712)); + points.Add(new DataPoint(354.2659988, 293.3499451)); + points.Add(new DataPoint(355.8602982, 293.1119995)); + points.Add(new DataPoint(357.197731, 292.2803345)); + points.Add(new DataPoint(358.3595047, 291.0731506)); + points.Add(new DataPoint(359.4267349, 289.7085876)); + points.Add(new DataPoint(360.4805679, 288.4048157)); + points.Add(new DataPoint(361.6021194, 287.3800049)); + points.Add(new DataPoint(362.8725357, 286.8523254)); + points.Add(new DataPoint(364.3729935, 287.0399475)); + points.Add(new DataPoint(365.9158707, 287.8427734)); + points.Add(new DataPoint(367.3995438, 289.0066833)); + points.Add(new DataPoint(370.1699905, 292.0510864)); + points.Add(new DataPoint(372.6456985, 295.4399109)); + points.Add(new DataPoint(374.788002, 298.4399719)); + points.Add(new DataPoint(394.8579788, 325.8149719)); + points.Add(new DataPoint(397.3873978, 329.0663757)); + points.Add(new DataPoint(399.9987259, 332.6233521)); + points.Add(new DataPoint(402.1026993, 336.3991089)); + points.Add(new DataPoint(402.7802811, 338.3419189)); + points.Add(new DataPoint(403.109993, 340.3069458)); + points.Add(new DataPoint(403.7992325, 340.2913818)); + points.Add(new DataPoint(404.1172256, 340.3743286)); + points.Add(new DataPoint(404.2001114, 340.691864)); + points.Add(new DataPoint(404.1839981, 341.3799744)); + points.Add(new DataPoint(405.9170609, 342.5977478)); + points.Add(new DataPoint(407.5672379, 344.3135681)); + points.Add(new DataPoint(410.6323624, 348.6974487)); + points.Add(new DataPoint(413.4063187, 353.4481201)); + points.Add(new DataPoint(414.6925125, 355.6223755)); + points.Add(new DataPoint(415.9159927, 357.4819641)); + points.Add(new DataPoint(446.1409988, 402.5239563)); + points.Add(new DataPoint(447.8941116, 404.6854248)); + points.Add(new DataPoint(449.9755325, 406.9086609)); + points.Add(new DataPoint(454.483345, 411.5653381)); + points.Add(new DataPoint(456.5896683, 414.0111694)); + points.Add(new DataPoint(458.3842239, 416.5435791)); + points.Add(new DataPoint(459.7070389, 419.1687927)); + points.Add(new DataPoint(460.3980179, 421.8929749)); + points.Add(new DataPoint(460.330513, 423.2209473)); + points.Add(new DataPoint(459.8673782, 424.4043274)); + points.Add(new DataPoint(458.1563797, 426.4813232)); + points.Add(new DataPoint(456.0694046, 428.4118958)); + points.Add(new DataPoint(454.4110184, 430.4839478)); + points.Add(new DataPoint(453.6341629, 432.6287231)); + points.Add(new DataPoint(453.2503738, 434.9552002)); + points.Add(new DataPoint(452.6709671, 439.6079712)); + points.Add(new DataPoint(451.6133499, 443.3995361)); + points.Add(new DataPoint(450.0984573, 447.2178345)); + points.Add(new DataPoint(448.1988602, 450.8544312)); + points.Add(new DataPoint(445.9870071, 454.1009521)); + points.Add(new DataPoint(445.2327957, 454.9499512)); + points.Add(new DataPoint(444.120369, 456.1347046)); + points.Add(new DataPoint(441.6337357, 459.0782166)); + points.Add(new DataPoint(440.6658401, 460.6203003)); + points.Add(new DataPoint(440.1524734, 462.0648193)); + points.Add(new DataPoint(440.2967911, 463.3034973)); + points.Add(new DataPoint(441.3020096, 464.2279663)); + points.Add(new DataPoint(443.0089798, 464.4325867)); + points.Add(new DataPoint(444.7705154, 463.7559509)); + points.Add(new DataPoint(446.3872757, 462.6180725)); + points.Add(new DataPoint(447.6599808, 461.4389648)); + points.Add(new DataPoint(449.96418, 458.7336426)); + points.Add(new DataPoint(451.896492, 455.7789612)); + points.Add(new DataPoint(454.7979813, 449.3179626)); + points.Add(new DataPoint(455.2873001, 447.6248474)); + points.Add(new DataPoint(455.8775101, 445.8508301)); + points.Add(new DataPoint(456.8382034, 444.3796387)); + points.Add(new DataPoint(458.4389725, 443.5949707)); + points.Add(new DataPoint(460.0345535, 443.7620239)); + points.Add(new DataPoint(461.7698441, 444.6128235)); + points.Add(new DataPoint(463.5780106, 445.9676208)); + points.Add(new DataPoint(465.3921585, 447.6465759)); + points.Add(new DataPoint(468.7708817, 451.2580566)); + points.Add(new DataPoint(470.2016678, 452.8309631)); + points.Add(new DataPoint(471.3709793, 454.0089722)); + points.Add(new DataPoint(478.8518143, 460.0104675)); + points.Add(new DataPoint(486.9943924, 465.3340759)); + points.Add(new DataPoint(495.4878006, 470.1171265)); + points.Add(new DataPoint(504.0210037, 474.4969482)); + points.Add(new DataPoint(509.5540848, 477.1457214)); + points.Add(new DataPoint(515.2860184, 479.3189697)); + points.Add(new DataPoint(516.4008255, 479.6032104)); + points.Add(new DataPoint(517.6022415, 479.6870728)); + points.Add(new DataPoint(518.5872879, 479.3061523)); + points.Add(new DataPoint(519.0529861, 478.1959534)); + points.Add(new DataPoint(518.8626175, 476.8864441)); + points.Add(new DataPoint(518.1857986, 475.7019958)); + points.Add(new DataPoint(515.84095, 473.7122192)); + points.Add(new DataPoint(512.9545975, 472.234314)); + points.Add(new DataPoint(510.4629593, 471.2759705)); + points.Add(new DataPoint(507.6074905, 470.256958)); + points.Add(new DataPoint(504.0599442, 468.8930969)); + points.Add(new DataPoint(496.255867, 465.2143555)); + points.Add(new DataPoint(492.682869, 462.9411621)); + points.Add(new DataPoint(489.7850418, 460.4066467)); + points.Add(new DataPoint(487.9041214, 457.6316223)); + points.Add(new DataPoint(487.4518509, 456.1604309)); + points.Add(new DataPoint(487.3819656, 454.6369629)); + points.Add(new DataPoint(491.1286697, 455.6597595)); + points.Add(new DataPoint(494.7612381, 457.2131958)); + points.Add(new DataPoint(498.3274002, 458.9732666)); + points.Add(new DataPoint(501.8750076, 460.6159668)); + points.Add(new DataPoint(508.6896439, 463.2619934)); + points.Add(new DataPoint(515.7986526, 465.5415649)); + points.Add(new DataPoint(523.0577469, 467.2131042)); + points.Add(new DataPoint(530.3230057, 468.0349731)); + points.Add(new DataPoint(536.5177689, 468.0764465)); + points.Add(new DataPoint(542.669014, 467.3979492)); + points.Add(new DataPoint(543.9200516, 466.9833069)); + points.Add(new DataPoint(545.0242386, 466.2348328)); + points.Add(new DataPoint(545.5588455, 465.2004089)); + points.Add(new DataPoint(545.1009598, 463.927948)); + points.Add(new DataPoint(544.175972, 463.0953064)); + points.Add(new DataPoint(542.9511795, 462.4622803)); + points.Add(new DataPoint(539.9430008, 461.6712036)); + points.Add(new DataPoint(536.7585526, 461.3072815)); + points.Add(new DataPoint(534.0799637, 461.1229553)); + points.Add(new DataPoint(520.8706131, 459.9545898)); + points.Add(new DataPoint(514.2815628, 459.0859985)); + points.Add(new DataPoint(507.7789993, 457.8509521)); + points.Add(new DataPoint(506.4525833, 457.5542603)); + points.Add(new DataPoint(504.8121414, 457.1582336)); + points.Add(new DataPoint(501.1944656, 455.9819641)); + points.Add(new DataPoint(499.5198441, 455.1585083)); + points.Add(new DataPoint(498.1362991, 454.1494141)); + points.Add(new DataPoint(497.1952591, 452.9331055)); + points.Add(new DataPoint(496.8479691, 451.4879456)); + points.Add(new DataPoint(497.117012, 450.6549377)); + points.Add(new DataPoint(497.8393021, 450.1732788)); + points.Add(new DataPoint(500.1341019, 449.9840698)); + points.Add(new DataPoint(502.7133255, 450.3605652)); + points.Add(new DataPoint(503.7911453, 450.5859985)); + points.Add(new DataPoint(504.557991, 450.7429504)); + points.Add(new DataPoint(511.3823318, 451.3563843)); + points.Add(new DataPoint(518.3227615, 451.0169373)); + points.Add(new DataPoint(525.2244949, 449.9740295)); + points.Add(new DataPoint(531.932991, 448.4769592)); + points.Add(new DataPoint(532.8128738, 448.2760315)); + points.Add(new DataPoint(534.1250076, 447.9761353)); + points.Add(new DataPoint(537.3393631, 447.0833435)); + points.Add(new DataPoint(538.8882523, 446.4923706)); + points.Add(new DataPoint(540.1627884, 445.8063354)); + points.Add(new DataPoint(540.9862747, 445.0262146)); + points.Add(new DataPoint(541.1820145, 444.1529541)); + points.Add(new DataPoint(540.6489334, 443.4705505)); + points.Add(new DataPoint(539.4853592, 443.0022888)); + points.Add(new DataPoint(537.8792191, 442.7068176)); + points.Add(new DataPoint(536.0183792, 442.5428467)); + points.Add(new DataPoint(532.2842484, 442.4439392)); + points.Add(new DataPoint(530.7866898, 442.4263916)); + points.Add(new DataPoint(529.7860184, 442.3749695)); + points.Add(new DataPoint(522.7177811, 441.8120117)); + points.Add(new DataPoint(515.5401077, 441.6993408)); + points.Add(new DataPoint(501.2470169, 442.2559509)); + points.Add(new DataPoint(498.6232986, 442.5908508)); + points.Add(new DataPoint(495.6024857, 442.9595947)); + points.Add(new DataPoint(492.7076492, 442.7930298)); + points.Add(new DataPoint(491.4709549, 442.3311157)); + points.Add(new DataPoint(490.4619827, 441.5219727)); + points.Add(new DataPoint(489.3800125, 439.9010925)); + points.Add(new DataPoint(488.6179276, 438.0290833)); + points.Add(new DataPoint(487.6418533, 433.8266907)); + points.Add(new DataPoint(486.7113724, 429.5046997)); + points.Add(new DataPoint(486.0061722, 427.4831848)); + points.Add(new DataPoint(485.0039749, 425.6529541)); + points.Add(new DataPoint(464.5570145, 397.51297)); + points.Add(new DataPoint(441.859993, 359.0939636)); + points.Add(new DataPoint(419.5407486, 322.4837036)); + points.Add(new DataPoint(397.7539749, 285.5569458)); + points.Add(new DataPoint(392.6534195, 277.3995361)); + points.Add(new DataPoint(387.2727432, 269.1647034)); + points.Add(new DataPoint(382.4174271, 260.6722412)); + points.Add(new DataPoint(380.4385147, 256.2730713)); + points.Add(new DataPoint(378.8929825, 251.7419434)); + points.Add(new DataPoint(378.4342422, 247.8017578)); + points.Add(new DataPoint(378.8919754, 243.618103)); + points.Add(new DataPoint(379.8762283, 239.4705811)); + points.Add(new DataPoint(380.9969864, 235.6389771)); + points.Add(new DataPoint(388.6119766, 208.7999878)); + points.Add(new DataPoint(391.0815811, 198.9997559)); + points.Add(new DataPoint(393.3593521, 188.8963623)); + points.Add(new DataPoint(395.3594131, 178.5748901)); + points.Add(new DataPoint(396.9958572, 168.1204834)); + points.Add(new DataPoint(398.1828384, 157.6182251)); + points.Add(new DataPoint(398.8344498, 147.1533203)); + points.Add(new DataPoint(398.8647842, 136.8108521)); + points.Add(new DataPoint(398.1879959, 126.6759644)); + points.Add(new DataPoint(395.2633438, 103.3844604)); + points.Add(new DataPoint(393.3301468, 91.60638428)); + points.Add(new DataPoint(390.9952469, 79.85656738)); + points.Add(new DataPoint(388.1928177, 68.22253418)); + points.Add(new DataPoint(384.8570328, 56.79168701)); + points.Add(new DataPoint(380.9220352, 45.65136719)); + points.Add(new DataPoint(376.3219986, 34.88897705)); + points.Add(new DataPoint(371.1558609, 23.22259521)); + points.Add(new DataPoint(366.6760025, 11.27197266)); + points.Add(new DataPoint(365.8827591, 9.214355469)); + points.Add(new DataPoint(365.0445023, 6.805603027)); + points.Add(new DataPoint(364.7049942, 4.406799316)); + points.Add(new DataPoint(364.892189, 3.323974609)); + points.Add(new DataPoint(365.4079971, 2.378967285)); + points.Add(new DataPoint(366.5955276, 1.439331055)); + points.Add(new DataPoint(368.2348099, 0.826660156)); + points.Add(new DataPoint(372.3311234, 0.333557129)); + points.Add(new DataPoint(376.6218643, 0.40246582)); + points.Add(new DataPoint(378.5041885, 0.4921875)); + points.Add(new DataPoint(380.0319901, 0.535949707)); + points.Add(new DataPoint(420.2889786, 0)); + points.Add(new DataPoint(527.1040115, 0)); + points.Add(new DataPoint(558.0751419, 0.09362793)); + points.Add(new DataPoint(573.5140457, 0.204589844)); + points.Add(new DataPoint(588.6629715, 0.352966309)); + points.Add(new DataPoint(588.6629715, 0.352966309)); + return points; + } + + [Example("Conway's Game of Life")] + public static PlotModel ConwayLife() + { + // http://en.wikipedia.org/wiki/Conway's_Game_of_Life + var model = new PlotModel { Title = "Conway's Game of Life", Subtitle = "Click the mouse to step to the next generation." }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + int m = 40; + int n = 40; + var matrix = new double[m, n]; + var ms = new MatrixSeries { Matrix = matrix }; + + Action blinker = (i, j) => { matrix[i, j] = matrix[i, j + 1] = matrix[i, j + 2] = 1; }; + Action glider = (i, j) => { matrix[i, j] = matrix[i + 1, j + 1] = matrix[i + 1, j + 2] = matrix[i + 2, j] = matrix[i + 2, j + 1] = 1; }; + Action rpentomino = (i, j) => { matrix[i, j + 1] = matrix[i, j + 2] = matrix[i + 1, j] = matrix[i + 1, j + 1] = matrix[i + 2, j + 1] = 1; }; + + blinker(2, 10); + glider(2, 2); + rpentomino(20, 20); + + model.Series.Add(ms); + int g = 0; + Action stepToNextGeneration = () => + { + var next = new double[m, n]; + for (int i = 1; i < m - 1; i++) + { + for (int j = 1; j < n - 1; j++) + { + int k = (int)(matrix[i - 1, j - 1] + matrix[i - 1, j] + matrix[i - 1, j + 1] + matrix[i, j - 1] + + matrix[i, j + 1] + matrix[i + 1, j - 1] + matrix[i + 1, j] + + matrix[i + 1, j + 1]); + + if (matrix[i, j].Equals(0) && k == 3) + { + // Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. + next[i, j] = 1; + continue; + } + + if (matrix[i, j].Equals(1) && (k == 2 || k == 3)) + { + // Any live cell with two or three live neighbours lives on to the next generation. + next[i, j] = 1; + } + + // Any live cell with fewer than two live neighbours dies, as if caused by under-population. + // Any live cell with more than three live neighbours dies, as if by overcrowding. + } + } + + g++; + ms.Title = "Generation " + g; + ms.Matrix = matrix = next; + model.InvalidatePlot(true); + }; + + model.MouseDown += (s, e) => + { + if (e.ChangedButton == OxyMouseButton.Left) + { + stepToNextGeneration(); + e.Handled = true; + } + }; + + return model; + } + + [Example("Mandelbrot custom series")] + public static PlotModel Mandelbrot() + { + // http://en.wikipedia.org/wiki/Mandelbrot_set + var model = new PlotModel { Title = "The Mandelbrot set" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -1.4, Maximum = 1.4 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -2, Maximum = 1 }); + model.Axes.Add( + new LinearColorAxis + { + Position = AxisPosition.Right, + Minimum = 0, + Maximum = 64, + Palette = OxyPalettes.Jet(64), + HighColor = OxyColors.Black + }); + model.Series.Add(new MandelbrotSetSeries()); + return model; + } + + [Example("Julia set custom series")] + public static PlotModel JuliaSet() + { + // http://en.wikipedia.org/wiki/Julia_set + var model = new PlotModel { Subtitle = "Click and move the mouse" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -2, Maximum = 2 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -2.5, Maximum = 2.5 }); + model.Axes.Add( + new LinearColorAxis + { + Position = AxisPosition.Right, + Minimum = 0, + Maximum = 64, + Palette = OxyPalettes.Jet(64), + HighColor = OxyColors.Black + }); + + var jss = new JuliaSetSeries(); + + // Delegate to set the c and title + Action setConstant = (c1, c2) => + { + jss.C1 = c1; + jss.C2 = c2; + model.Title = string.Format("The Julia set, c={0:0.00000}+{1:0.00000}i", jss.C1, jss.C2); + }; + + // Update the c by the position where the mouse was clicked/moved + Action handleMouseEvent = e => + { + var c = jss.InverseTransform(e.Position); + setConstant(c.X, c.Y); + model.InvalidatePlot(true); + e.Handled = true; + }; + jss.MouseDown += (s, e) => handleMouseEvent(e); + jss.MouseMove += (s, e) => handleMouseEvent(e); + + // set the initial c + setConstant(-0.726895347709114071439, 0.188887129043845954792); + + model.Series.Add(jss); + return model; + } + + [Example("Elephant curve")] + public static PlotModel ElephantCurve() + { + // http://www.wolframalpha.com/input/?i=elephant+curve + // See also https://gist.github.com/purem/4687549/raw/8dda1f16cc70469aedecec19af1530534eadbae3/Wolfram+alpha+named+parametric+curves + Func sin = Math.Sin; + Func x = + t => + -27d / 5 * sin(3d / 2 - 30 * t) - 16d / 3 * sin(9d / 8 - 29 * t) - 29d / 5 * sin(5d / 4 - 27 * t) + - 8d / 3 * sin(1d / 4 - 26 * t) - 25d / 7 * sin(1d / 3 - 25 * t) - 31d / 4 * sin(4d / 7 - 22 * t) + - 25d / 4 * sin(4d / 3 - 20 * t) - 33d / 2 * sin(2d / 3 - 19 * t) - 67d / 4 * sin(6d / 5 - 16 * t) + - 100d / 11 * sin(1d / 4 - 10 * t) - 425d / 7 * sin(1 - 4 * t) + 149d / 4 * sin(8 * t) + + 1172d / 3 * sin(t + 21d / 5) + 661d / 11 * sin(2 * t + 3) + 471d / 8 * sin(3 * t + 10d / 7) + + 211d / 7 * sin(5 * t + 13d / 4) + 39d / 4 * sin(6 * t + 10d / 7) + 139d / 10 * sin(7 * t + 7d / 6) + + 77d / 3 * sin(9 * t + 18d / 7) + 135d / 8 * sin(11 * t + 1d / 2) + 23d / 4 * sin(12 * t + 8d / 5) + + 95d / 4 * sin(13 * t + 4) + 31d / 4 * sin(14 * t + 3d / 5) + 67d / 11 * sin(15 * t + 7d / 3) + + 127d / 21 * sin(17 * t + 17d / 4) + 95d / 8 * sin(18 * t + 7d / 8) + + 32d / 11 * sin(21 * t + 8d / 3) + 81d / 10 * sin(23 * t + 45d / 11) + + 13d / 3 * sin(24 * t + 13d / 4) + 7d / 4 * sin(28 * t + 3d / 2) + 11d / 5 * sin(31 * t + 5d / 2) + + 1d / 3 * sin(32 * t + 12d / 5) + 13d / 4 * sin(33 * t + 22d / 5) + 14d / 3 * sin(34 * t + 9d / 4) + + 9d / 5 * sin(35 * t + 8d / 5) + 17d / 9 * sin(36 * t + 22d / 5) + 1d / 3 * sin(37 * t + 15d / 7) + + 3d / 2 * sin(38 * t + 39d / 10) + 4d / 3 * sin(39 * t + 7d / 2) + 5d / 3 * sin(40 * t + 17d / 6); + Func y = + t => + -13d / 7 * sin(1d / 2 - 40 * t) - 31d / 8 * sin(1d / 11 - 34 * t) - 12d / 5 * sin(1d / 4 - 31 * t) + - 9d / 4 * sin(4d / 3 - 29 * t) - 5d / 3 * sin(4d / 3 - 28 * t) - 11d / 2 * sin(6d / 5 - 26 * t) + - 17d / 7 * sin(3d / 2 - 25 * t) - 5d / 2 * sin(1 - 24 * t) - 39d / 7 * sin(1 - 19 * t) + - 59d / 5 * sin(2d / 3 - 18 * t) - 179d / 9 * sin(13d / 12 - 12 * t) + - 103d / 2 * sin(1d / 10 - 9 * t) - 356d / 5 * sin(1 - 5 * t) - 429d / 2 * sin(20d / 19 - t) + + 288d / 5 * sin(2 * t + 10d / 3) + 53d / 6 * sin(3 * t + 5d / 2) + 351d / 7 * sin(4 * t + 5d / 2) + + 201d / 4 * sin(6 * t + 17d / 7) + 167d / 3 * sin(7 * t + 19d / 5) + 323d / 5 * sin(8 * t + 1d / 4) + + 153d / 7 * sin(10 * t + 2d / 3) + 71d / 5 * sin(11 * t + 6d / 5) + + 47d / 12 * sin(13 * t + 11d / 5) + 391d / 26 * sin(14 * t + 2) + 164d / 11 * sin(15 * t + 1d / 7) + + 11d / 2 * sin(16 * t + 2d / 3) + 31d / 3 * sin(17 * t + 1d / 7) + 54d / 11 * sin(20 * t + 1d / 4) + + 43d / 5 * sin(21 * t + 13d / 3) + 13d / 5 * sin(22 * t + 3d / 2) + 17d / 5 * sin(23 * t + 11d / 5) + + 19d / 10 * sin(27 * t + 4) + 15d / 2 * sin(30 * t + 55d / 18) + 4d / 3 * sin(32 * t + 3d / 5) + + 5d / 3 * sin(33 * t + 4) + 27d / 7 * sin(35 * t + 13d / 6) + 1d / 4 * sin(36 * t + 43d / 11) + + 16d / 5 * sin(37 * t + 9d / 2) + 20d / 19 * sin(38 * t + 23d / 6) + 8d / 3 * sin(39 * t + 4d / 7); + + var model = new PlotModel { Title = "Elephant curve", PlotType = PlotType.Cartesian }; + model.Series.Add(new FunctionSeries(x, y, 0, Math.PI * 2, 1000)); + return model; + } + + [Example("PI curve")] + public static PlotModel PiCurve() + { + // http://www.wolframalpha.com/input/?i=pi+curve + Func sin = Math.Sin; + Func x = + t => 17d / 31 * sin(235d / 57 - 32 * t) + 19d / 17 * sin(192d / 55 - 30 * t) + 47d / 32 * sin(69d / 25 - 29 * t) + 35d / 26 * sin(75d / 34 - 27 * t) + 6d / 31 * sin(23d / 10 - 26 * t) + 35d / 43 * sin(10d / 33 - 25 * t) + 126d / 43 * sin(421d / 158 - 24 * t) + 143d / 57 * sin(35d / 22 - 22 * t) + 106d / 27 * sin(84d / 29 - 21 * t) + 88d / 25 * sin(23d / 27 - 20 * t) + 74d / 27 * sin(53d / 22 - 19 * t) + 44d / 53 * sin(117d / 25 - 18 * t) + 126d / 25 * sin(88d / 49 - 17 * t) + 79d / 11 * sin(43d / 26 - 16 * t) + 43d / 12 * sin(41d / 17 - 15 * t) + 47d / 27 * sin(244d / 81 - 14 * t) + 8d / 5 * sin(79d / 19 - 13 * t) + 373d / 46 * sin(109d / 38 - 12 * t) + 1200d / 31 * sin(133d / 74 - 11 * t) + 67d / 24 * sin(157d / 61 - 10 * t) + 583d / 28 * sin(13d / 8 - 8 * t) + 772d / 35 * sin(59d / 16 - 7 * t) + 3705d / 46 * sin(117d / 50 - 6 * t) + 862d / 13 * sin(19d / 8 - 5 * t) + 6555d / 34 * sin(157d / 78 - 3 * t) + 6949d / 13 * sin(83d / 27 - t) - 6805d / 54 * sin(2 * t + 1d / 145) - 5207d / 37 * sin(4 * t + 49d / 74) - 1811d / 58 * sin(9 * t + 55d / 43) - 63d / 20 * sin(23 * t + 2d / 23) - 266d / 177 * sin(28 * t + 13d / 18) - 2d / 21 * sin(31 * t + 7d / 16); + Func y = + t => 70d / 37 * sin(65d / 32 - 32 * t) + 11d / 12 * sin(98d / 41 - 31 * t) + 26d / 29 * sin(35d / 12 - 30 * t) + 54d / 41 * sin(18d / 7 - 29 * t) + 177d / 71 * sin(51d / 19 - 27 * t) + 59d / 34 * sin(125d / 33 - 26 * t) + 49d / 29 * sin(18d / 11 - 25 * t) + 151d / 75 * sin(59d / 22 - 24 * t) + 52d / 9 * sin(118d / 45 - 22 * t) + 52d / 33 * sin(133d / 52 - 21 * t) + 37d / 45 * sin(61d / 14 - 20 * t) + 143d / 46 * sin(144d / 41 - 19 * t) + 254d / 47 * sin(19d / 52 - 18 * t) + 246d / 35 * sin(92d / 25 - 17 * t) + 722d / 111 * sin(176d / 67 - 16 * t) + 136d / 23 * sin(3d / 19 - 15 * t) + 273d / 25 * sin(32d / 21 - 13 * t) + 229d / 33 * sin(117d / 28 - 12 * t) + 19d / 4 * sin(43d / 11 - 11 * t) + 135d / 8 * sin(23d / 10 - 10 * t) + 205d / 6 * sin(33d / 23 - 8 * t) + 679d / 45 * sin(55d / 12 - 7 * t) + 101d / 8 * sin(11d / 12 - 6 * t) + 2760d / 59 * sin(40d / 11 - 5 * t) + 1207d / 18 * sin(21d / 23 - 4 * t) + 8566d / 27 * sin(39d / 28 - 3 * t) + 12334d / 29 * sin(47d / 37 - 2 * t) + 15410d / 39 * sin(185d / 41 - t) - 596d / 17 * sin(9 * t + 3d / 26) - 247d / 28 * sin(14 * t + 25d / 21) - 458d / 131 * sin(23 * t + 21d / 37) - 41d / 36 * sin(28 * t + 7d / 8); + + var model = new PlotModel { Title = "PI curve", PlotType = PlotType.Cartesian }; + model.Series.Add(new FunctionSeries(x, y, 0, Math.PI * 2, 1000)); + return model; + } + + [Example("Angelina Jolie curve")] + public static PlotModel AngelinaJolieCurve() + { + // http://www.wolframalpha.com/input/?i=Angelina+Jolie+curve + + // Heaviside step function + Func theta = x => x < 0 ? 0 : 1; + + Func sin = Math.Sin; + double pi = Math.PI; + Func xt = + t => + ((-23d / 4 * sin(29d / 20 - 41 * t) - 47d / 15 * sin(47d / 34 - 38 * t) + - 979d / 196 * sin(45d / 31 - 36 * t) - 59d / 6 * sin(25d / 17 - 33 * t) + - 259d / 26 * sin(104d / 69 - 32 * t) - 49d / 24 * sin(57d / 37 - 31 * t) + - 37d / 21 * sin(32d / 23 - 30 * t) - 324d / 31 * sin(85d / 57 - 27 * t) + - 47d / 26 * sin(24d / 17 - 25 * t) - 247d / 29 * sin(39d / 25 - 24 * t) + - 834d / 71 * sin(63d / 41 - 23 * t) - 475d / 49 * sin(62d / 41 - 22 * t) + - 20d / 7 * sin(29d / 20 - 17 * t) - 1286d / 61 * sin(98d / 65 - 16 * t) + - 2312d / 25 * sin(20d / 13 - 14 * t) - 2662d / 41 * sin(23d / 15 - 13 * t) + - 2292d / 131 * sin(92d / 61 - 11 * t) - 1690d / 37 * sin(48d / 31 - 8 * t) + + 993d / 23 * sin(t + 52d / 33) + 407d / 31 * sin(2 * t + 25d / 16) + + 1049d / 57 * sin(3 * t + 49d / 31) + 1385d / 42 * sin(4 * t + 80d / 17) + + 2929d / 40 * sin(5 * t + 49d / 31) + 500d / 39 * sin(6 * t + 164d / 35) + + 116d / 25 * sin(7 * t + 155d / 33) + 2593d / 26 * sin(9 * t + 43d / 27) + + 200d / 37 * sin(10 * t + 65d / 42) + 2866d / 39 * sin(12 * t + 133d / 83) + + 703d / 234 * sin(15 * t + 46d / 27) + 133d / 8 * sin(18 * t + 13d / 8) + + 716d / 33 * sin(19 * t + 27d / 17) + 180d / 53 * sin(20 * t + 47d / 30) + + 476d / 31 * sin(21 * t + 57d / 35) + 73d / 22 * sin(26 * t + 77d / 48) + + 549d / 49 * sin(28 * t + 44d / 27) + 657d / 68 * sin(29 * t + 27d / 17) + + 29d / 22 * sin(34 * t + 140d / 31) + 180d / 49 * sin(35 * t + 14d / 9) + + 43d / 4 * sin(37 * t + 77d / 46) + 68d / 23 * sin(39 * t + 39d / 25) + + 80d / 47 * sin(40 * t + 49d / 27) + 16829d / 29) * theta(119 * pi - t) + * theta(t - 115 * pi) + + (-43d / 40 * sin(39d / 29 - 62 * t) - 44d / 17 * sin(56d / 37 - 58 * t) + - 23d / 39 * sin(14d / 11 - 57 * t) - 59d / 10 * sin(49d / 32 - 51 * t) + - 215d / 31 * sin(20d / 13 - 46 * t) - 447d / 22 * sin(110d / 73 - 34 * t) + - 407d / 39 * sin(54d / 35 - 33 * t) - 432d / 35 * sin(14d / 9 - 29 * t) + - 175d / 33 * sin(35d / 24 - 28 * t) - 102d / 5 * sin(64d / 41 - 22 * t) + + 833d / 46 * sin(t + 131d / 28) + 1360d / 9 * sin(2 * t + 52d / 33) + + 139d / 3 * sin(3 * t + 43d / 27) + 108d / 29 * sin(4 * t + 244d / 53) + + 4269d / 41 * sin(5 * t + 113d / 24) + 7407d / 31 * sin(6 * t + 65d / 41) + + 2159d / 32 * sin(7 * t + 103d / 22) + 5476d / 51 * sin(8 * t + 37d / 23) + + 3855d / 37 * sin(9 * t + 60d / 37) + 2247d / 46 * sin(10 * t + 18d / 11) + + 216d / 31 * sin(11 * t + 81d / 40) + 3364d / 35 * sin(12 * t + 69d / 43) + + 1492d / 21 * sin(13 * t + 47d / 10) + 1981d / 29 * sin(14 * t + 21d / 13) + + 1852d / 35 * sin(15 * t + 18d / 11) + 255d / 23 * sin(16 * t + 72d / 41) + + 499d / 25 * sin(17 * t + 134d / 29) + 754d / 17 * sin(18 * t + 57d / 35) + + 203d / 31 * sin(19 * t + 35d / 19) + 1289d / 32 * sin(20 * t + 41d / 25) + + 65d / 21 * sin(21 * t + 55d / 13) + 731d / 31 * sin(23 * t + 34d / 21) + + 816d / 83 * sin(24 * t + 23d / 14) + 467d / 29 * sin(25 * t + 197d / 42) + + 496d / 37 * sin(26 * t + 64d / 39) + 34d / 9 * sin(27 * t + 40d / 27) + + 204d / 23 * sin(30 * t + 76d / 43) + 34d / 3 * sin(31 * t + 50d / 29) + + 1579d / 57 * sin(32 * t + 51d / 31) + 37d / 6 * sin(35 * t + 69d / 44) + + 128d / 21 * sin(36 * t + 21d / 13) + 194d / 83 * sin(37 * t + 52d / 27) + + 35d / 37 * sin(38 * t + 46d / 19) + 39d / 38 * sin(39 * t + 234d / 55) + + 113d / 16 * sin(40 * t + 71d / 43) + 126d / 101 * sin(41 * t + 145d / 83) + + 13d / 6 * sin(42 * t + 184d / 41) + 100d / 31 * sin(43 * t + 117d / 25) + + 355d / 36 * sin(44 * t + 48d / 29) + 148d / 57 * sin(45 * t + 30d / 17) + + 3d / 2 * sin(47 * t + 51d / 28) + 107d / 61 * sin(48 * t + 27d / 16) + + 72d / 13 * sin(49 * t + 93d / 56) + 55d / 37 * sin(50 * t + 144d / 31) + + 53d / 24 * sin(52 * t + 59d / 34) + 182d / 47 * sin(53 * t + 41d / 24) + + 481d / 103 * sin(54 * t + 110d / 61) + 97d / 29 * sin(55 * t + 89d / 19) + + 7d / 4 * sin(56 * t + 49d / 30) + 82d / 37 * sin(59 * t + 55d / 28) + + 20d / 13 * sin(60 * t + 45d / 23) + 147d / 34 * sin(61 * t + 77d / 45) - 27563d / 35) + * theta(115 * pi - t) * theta(t - 111 * pi) + + (-11d / 13 * sin(37d / 33 - 98 * t) - 13d / 32 * sin(69d / 44 - 97 * t) + - 33d / 19 * sin(38d / 29 - 88 * t) - 124d / 45 * sin(44d / 29 - 87 * t) + - 72d / 37 * sin(56d / 43 - 77 * t) - 78d / 77 * sin(197d / 131 - 72 * t) + - 39d / 58 * sin(7d / 33 - 54 * t) - 31d / 20 * sin(26d / 25 - 37 * t) + - 265d / 58 * sin(122d / 81 - 35 * t) - 4901d / 196 * sin(49d / 32 - 12 * t) + - 7950d / 49 * sin(91d / 58 - 8 * t) - 515d / 12 * sin(25d / 16 - 5 * t) + + 21289d / 23 * sin(t + 80d / 51) + 4245d / 8 * sin(2 * t + 36d / 23) + + 394321d / 930 * sin(3 * t + 113d / 24) + 4699d / 17 * sin(4 * t + 113d / 24) + + 1931d / 41 * sin(6 * t + 43d / 28) + 745d / 24 * sin(7 * t + 40d / 27) + + 861d / 8 * sin(9 * t + 113d / 24) + 1348d / 15 * sin(10 * t + 146d / 31) + + 1015d / 39 * sin(11 * t + 43d / 28) + 590d / 39 * sin(13 * t + 53d / 34) + + 271d / 37 * sin(14 * t + 48d / 31) + 268d / 29 * sin(15 * t + 63d / 38) + + 443d / 25 * sin(16 * t + 127d / 27) + 872d / 37 * sin(17 * t + 53d / 35) + + 2329d / 82 * sin(18 * t + 145d / 31) + 11d / 4 * sin(19 * t + 832d / 185) + + 1139d / 36 * sin(20 * t + 49d / 32) + 203d / 13 * sin(21 * t + 114d / 25) + + 2807d / 72 * sin(22 * t + 48d / 31) + 639d / 26 * sin(23 * t + 19d / 12) + + 163d / 23 * sin(24 * t + 43d / 26) + 517d / 36 * sin(25 * t + 75d / 47) + + 359d / 30 * sin(26 * t + 159d / 34) + 603d / 32 * sin(27 * t + 46d / 31) + + 1679d / 34 * sin(28 * t + 387d / 83) + 269d / 22 * sin(29 * t + 41d / 28) + + 94d / 39 * sin(30 * t + 56d / 51) + 1219d / 54 * sin(31 * t + 51d / 11) + + 535d / 29 * sin(32 * t + 61d / 41) + 17d / 52 * sin(33 * t + 54d / 49) + + 133d / 33 * sin(34 * t + 308d / 67) + 73d / 18 * sin(36 * t + 262d / 57) + + 131d / 20 * sin(38 * t + 134d / 29) + 391d / 72 * sin(39 * t + 428d / 93) + + 505d / 26 * sin(40 * t + 3d / 2) + 39d / 10 * sin(41 * t + 256d / 57) + + 76d / 21 * sin(42 * t + 22d / 13) + 341d / 37 * sin(43 * t + 16d / 11) + + 67d / 39 * sin(44 * t + 93d / 22) + 211d / 26 * sin(45 * t + 167d / 36) + + 161d / 20 * sin(46 * t + 19d / 13) + 175d / 23 * sin(47 * t + 124d / 27) + + 229d / 35 * sin(48 * t + 59d / 39) + 23d / 19 * sin(49 * t + 36d / 23) + + 59d / 34 * sin(50 * t + 40d / 9) + 399d / 46 * sin(51 * t + 75d / 52) + + 351d / 49 * sin(52 * t + 119d / 26) + 23d / 17 * sin(53 * t + 49d / 44) + + 179d / 17 * sin(55 * t + 308d / 67) + 74d / 25 * sin(56 * t + 84d / 61) + + 7d / 10 * sin(57 * t + 21d / 17) + 58d / 39 * sin(58 * t + 94d / 21) + + 44d / 23 * sin(59 * t + 97d / 54) + 265d / 36 * sin(60 * t + 47d / 32) + + 44d / 87 * sin(61 * t + 49d / 26) + 899d / 142 * sin(62 * t + 143d / 31) + + 109d / 29 * sin(63 * t + 93d / 70) + 391d / 55 * sin(64 * t + 51d / 11) + + 24d / 37 * sin(65 * t + 29d / 38) + 151d / 30 * sin(66 * t + 78d / 17) + + 291d / 50 * sin(67 * t + 44d / 29) + 124d / 29 * sin(68 * t + 82d / 55) + + 83d / 52 * sin(69 * t + 95d / 47) + 22d / 21 * sin(70 * t + 81d / 38) + + 301d / 47 * sin(71 * t + 13d / 9) + 341d / 28 * sin(73 * t + 239d / 52) + + 133d / 22 * sin(74 * t + 14d / 11) + 245d / 39 * sin(75 * t + 47d / 10) + + 136d / 29 * sin(76 * t + 537d / 115) + 250d / 43 * sin(78 * t + 25d / 17) + + 30d / 41 * sin(79 * t + 83d / 23) + 5d / 2 * sin(80 * t + 198d / 113) + + 129d / 29 * sin(81 * t + 21d / 13) + 169d / 32 * sin(82 * t + 73d / 47) + + 28d / 29 * sin(83 * t + 133d / 33) + 129d / 40 * sin(84 * t + 86d / 19) + + 34d / 11 * sin(85 * t + 56d / 43) + 143d / 32 * sin(86 * t + 163d / 35) + + 77d / 25 * sin(89 * t + 27d / 20) + 418d / 93 * sin(90 * t + 166d / 37) + + 103d / 37 * sin(91 * t + 55d / 39) + 16d / 13 * sin(92 * t + 45d / 26) + + 87d / 40 * sin(93 * t + 55d / 32) + 53d / 25 * sin(94 * t + 67d / 41) + + 58d / 43 * sin(95 * t + 26d / 15) + 67d / 30 * sin(96 * t + 149d / 99) + + 155d / 41 * sin(99 * t + 124d / 27) - 6637d / 21) * theta(111 * pi - t) + * theta(t - 107 * pi) + + (-27d / 23 * sin(5d / 12 - 35 * t) - 94d / 23 * sin(32d / 31 - 34 * t) + - 26d / 9 * sin(17d / 27 - 33 * t) - 226d / 31 * sin(43d / 33 - 32 * t) + - 211d / 50 * sin(38d / 25 - 29 * t) - 11d / 18 * sin(18d / 23 - 28 * t) + - 23d / 18 * sin(32d / 31 - 27 * t) - 255d / 94 * sin(27d / 20 - 25 * t) + - 41d / 31 * sin(65d / 47 - 21 * t) - 59d / 12 * sin(33d / 28 - 19 * t) + - 160d / 31 * sin(31d / 29 - 18 * t) - 859d / 78 * sin(165d / 124 - 17 * t) + - 137d / 13 * sin(37d / 26 - 16 * t) - 25d / 23 * sin(175d / 117 - 9 * t) + + 937d / 6 * sin(t + 41d / 26) + 41d / 9 * sin(2 * t + 163d / 36) + + 563d / 33 * sin(3 * t + 21d / 13) + 19d / 8 * sin(4 * t + 181d / 40) + + 53d / 15 * sin(5 * t + 77d / 46) + 10d / 31 * sin(6 * t + 73d / 23) + + 133d / 39 * sin(7 * t + 67d / 42) + 5d / 9 * sin(8 * t + 30d / 19) + + 22d / 13 * sin(10 * t + 47d / 27) + 108d / 37 * sin(11 * t + 90d / 53) + + 37d / 40 * sin(12 * t + 47d / 23) + 18d / 13 * sin(13 * t + 49d / 11) + + 63d / 40 * sin(14 * t + 139d / 31) + 453d / 34 * sin(15 * t + 65d / 41) + + 27d / 32 * sin(20 * t + 13d / 46) + 8d / 19 * sin(22 * t + 58d / 35) + + 19d / 30 * sin(23 * t + 157d / 34) + 10d / 23 * sin(24 * t + 7d / 27) + + 51d / 31 * sin(26 * t + 29d / 24) + 83d / 26 * sin(30 * t + 52d / 31) + + 179d / 45 * sin(31 * t + 56d / 37) + 14d / 23 * sin(36 * t + 45d / 29) + + 56d / 33 * sin(37 * t + 69d / 37) + 62d / 61 * sin(38 * t + 192d / 47) + + 4d / 5 * sin(39 * t + 102d / 47) + 7d / 43 * sin(40 * t + 67d / 18) + + 3d / 13 * sin(41 * t + 39d / 38) + 15d / 32 * sin(42 * t + 75d / 16) + + 34d / 31 * sin(43 * t + 53d / 29) + 31d / 32 * sin(44 * t + 52d / 25) + + 11d / 29 * sin(45 * t + 23d / 6) + 19d / 11 * sin(46 * t + 134d / 29) + + 55d / 27 * sin(47 * t + 30d / 17) + 8d / 25 * sin(48 * t + 185d / 44) + + 12d / 31 * sin(49 * t + 61d / 41) - 803d / 16) * theta(107 * pi - t) + * theta(t - 103 * pi) + + (-183d / 137 * sin(41d / 31 - 53 * t) - 3d / 2 * sin(45d / 32 - 51 * t) + - 21d / 37 * sin(17d / 24 - 50 * t) - 109d / 73 * sin(21d / 16 - 49 * t) + - 28d / 23 * sin(26d / 19 - 46 * t) - 499d / 95 * sin(49d / 38 - 44 * t) + - 79d / 37 * sin(37d / 28 - 41 * t) - 28d / 25 * sin(35d / 33 - 35 * t) + - 39d / 10 * sin(23d / 17 - 34 * t) - 17d / 6 * sin(27d / 22 - 33 * t) + - 40d / 29 * sin(4d / 3 - 32 * t) - 159d / 65 * sin(23d / 16 - 30 * t) + - 130d / 31 * sin(43d / 34 - 29 * t) - 182d / 27 * sin(37d / 26 - 28 * t) + - 19d / 13 * sin(35d / 23 - 26 * t) - 67d / 39 * sin(58d / 49 - 25 * t) + - 131d / 37 * sin(81d / 59 - 24 * t) - 29d / 18 * sin(53d / 40 - 23 * t) + - 77d / 51 * sin(14d / 11 - 22 * t) - 457d / 61 * sin(68d / 47 - 21 * t) + - 293d / 27 * sin(53d / 36 - 15 * t) - 80d / 39 * sin(23d / 15 - 14 * t) + - 65d / 17 * sin(31d / 21 - 11 * t) - 21d / 17 * sin(26d / 17 - 10 * t) + - 41d / 13 * sin(57d / 37 - 8 * t) + 17496d / 85 * sin(t + 41d / 26) + + 26d / 17 * sin(2 * t + 418d / 93) + 449d / 24 * sin(3 * t + 27d / 17) + + 221d / 63 * sin(4 * t + 51d / 11) + 283d / 43 * sin(5 * t + 69d / 43) + + 16d / 15 * sin(6 * t + 64d / 37) + 29d / 11 * sin(7 * t + 59d / 36) + + 201d / 44 * sin(9 * t + 59d / 37) + 97d / 83 * sin(12 * t + 35d / 22) + + 77d / 10 * sin(13 * t + 173d / 104) + 23d / 22 * sin(16 * t + 61d / 32) + + 349d / 32 * sin(17 * t + 61d / 36) + 60d / 17 * sin(18 * t + 79d / 46) + + 11d / 23 * sin(19 * t + 61d / 29) + 373d / 86 * sin(20 * t + 48d / 29) + + 99d / 16 * sin(27 * t + 67d / 40) + 217d / 38 * sin(31 * t + 46d / 27) + + 25d / 29 * sin(36 * t + 189d / 41) + 423d / 106 * sin(37 * t + 49d / 27) + + 11d / 12 * sin(38 * t + 59d / 29) + 184d / 105 * sin(39 * t + 65d / 34) + + 93d / 50 * sin(40 * t + 93d / 49) + 8d / 25 * sin(42 * t + 45d / 22) + + 13d / 11 * sin(43 * t + 46d / 29) + 19d / 28 * sin(45 * t + 27d / 28) + + 14d / 23 * sin(47 * t + 37d / 31) + 9d / 31 * sin(48 * t + 25d / 16) + + 52d / 31 * sin(52 * t + 56d / 31) - 20749d / 273) * theta(103 * pi - t) + * theta(t - 99 * pi) + + (-2d / 27 * sin(47d / 30 - 3 * t) + 321d / 16 * sin(t + 63d / 40) + + 219d / 31 * sin(2 * t + 41d / 26) + 69d / 47 * sin(4 * t + 30d / 19) + + 36d / 23 * sin(5 * t + 27d / 17) + 888d / 11) * theta(99 * pi - t) + * theta(t - 95 * pi) + + (-93d / 25 * sin(25d / 16 - 8 * t) - 85d / 33 * sin(25d / 16 - 7 * t) + - 217d / 38 * sin(47d / 30 - 6 * t) - 989d / 49 * sin(25d / 16 - 5 * t) + + 6925d / 39 * sin(t + 11d / 7) + 3173d / 138 * sin(2 * t + 52d / 33) + + 289d / 9 * sin(3 * t + 146d / 31) + 187d / 23 * sin(4 * t + 41d / 26) + + 16d / 7 * sin(9 * t + 164d / 35) + 19d / 22 * sin(10 * t + 429d / 92) + + 4d / 27 * sin(11 * t + 47d / 32) + 23d / 40 * sin(12 * t + 29d / 19) - 1249d / 41) + * theta(95 * pi - t) * theta(t - 91 * pi) + + (-14d / 51 * sin(65d / 43 - 4 * t) + 2519d / 13 * sin(t + 74d / 47) + + 14d / 11 * sin(2 * t + 151d / 33) + 601d / 28 * sin(3 * t + 30d / 19) - 5627d / 23) + * theta(91 * pi - t) * theta(t - 87 * pi) + + (-268d / 37 * sin(91d / 58 - t) + 1d / 47 * sin(2 * t + 31d / 22) + + 68d / 41 * sin(3 * t + 113d / 24) + 185d / 19 * sin(4 * t + 52d / 33) + + 133d / 53 * sin(5 * t + 65d / 41) + 3d / 35 * sin(6 * t + 122d / 65) - 14306d / 33) + * theta(87 * pi - t) * theta(t - 83 * pi) + + (-64d / 15 * sin(66d / 43 - 12 * t) - 244d / 63 * sin(38d / 25 - 10 * t) + - 6d / 5 * sin(17d / 12 - 9 * t) - 632d / 39 * sin(20d / 13 - 8 * t) + - 986d / 33 * sin(20d / 13 - 7 * t) - 123d / 23 * sin(31d / 20 - 6 * t) + - 923d / 32 * sin(36d / 23 - 4 * t) + 1270d / 19 * sin(t + 74d / 47) + + 70d / 19 * sin(2 * t + 53d / 32) + 1359d / 43 * sin(3 * t + 41d / 26) + + 854d / 27 * sin(5 * t + 30d / 19) + 32d / 13 * sin(11 * t + 19d / 12) + 15881d / 49) + * theta(83 * pi - t) * theta(t - 79 * pi) + + (-1009d / 28 * sin(36d / 23 - 6 * t) + 1362d / 19 * sin(t + 11d / 7) + + 113d / 11 * sin(2 * t + 174d / 37) + 2128d / 45 * sin(3 * t + 30d / 19) + + 3805d / 58 * sin(4 * t + 30d / 19) + 1316d / 51 * sin(5 * t + 41d / 26) + + 500d / 33 * sin(7 * t + 85d / 54) + 69d / 8 * sin(8 * t + 179d / 38) + + 337d / 37 * sin(9 * t + 19d / 12) + 59d / 18 * sin(10 * t + 53d / 33) + + 5d / 24 * sin(11 * t + 87d / 46) + 335d / 44 * sin(12 * t + 46d / 29) - 9149d / 24) + * theta(79 * pi - t) * theta(t - 75 * pi) + + (-3d / 32 * sin(37d / 27 - 14 * t) - 31d / 25 * sin(54d / 35 - 11 * t) + - 101d / 51 * sin(39d / 25 - 6 * t) + 4553d / 33 * sin(t + 63d / 40) + + 771d / 43 * sin(2 * t + 65d / 41) + 679d / 45 * sin(3 * t + 49d / 31) + + 79d / 19 * sin(4 * t + 65d / 41) + 468d / 67 * sin(5 * t + 68d / 43) + + 127d / 52 * sin(7 * t + 59d / 37) + 30d / 29 * sin(8 * t + 155d / 33) + + 89d / 49 * sin(9 * t + 35d / 22) + 50d / 99 * sin(10 * t + 19d / 12) + + 35d / 52 * sin(12 * t + 49d / 30) + 80d / 39 * sin(13 * t + 21d / 13) + + 25d / 23 * sin(15 * t + 34d / 21) + 13d / 38 * sin(16 * t + 96d / 61) + + 17d / 31 * sin(17 * t + 17d / 10) + 55d / 39 * sin(18 * t + 61d / 38) + + 17d / 32 * sin(19 * t + 179d / 38) + 16d / 13 * sin(20 * t + 55d / 34) + 10772d / 39) + * theta(75 * pi - t) * theta(t - 71 * pi) + + (-sin(54d / 35 - 16 * t) - 17d / 29 * sin(86d / 57 - 12 * t) + - 43d / 19 * sin(47d / 30 - 2 * t) + 4197d / 25 * sin(t + 11d / 7) + + 904d / 39 * sin(3 * t + 36d / 23) + 6d / 11 * sin(4 * t + 127d / 27) + + 209d / 31 * sin(5 * t + 85d / 54) + 12d / 61 * sin(6 * t + 41d / 34) + + 143d / 46 * sin(7 * t + 14d / 9) + 28d / 29 * sin(8 * t + 30d / 19) + + 63d / 32 * sin(9 * t + 36d / 23) + 17d / 43 * sin(10 * t + 149d / 32) + + 29d / 19 * sin(11 * t + 25d / 16) + 5d / 8 * sin(13 * t + 36d / 23) + + 21d / 17 * sin(14 * t + 61d / 39) + 28d / 57 * sin(15 * t + 39d / 25) + + 19d / 31 * sin(17 * t + 49d / 31) + 25d / 42 * sin(18 * t + 127d / 27) + + 17d / 25 * sin(19 * t + 74d / 47) + 5d / 19 * sin(20 * t + 32d / 21) + + 62d / 55 * sin(21 * t + 47d / 30) - 14987d / 44) * theta(71 * pi - t) + * theta(t - 67 * pi) + + (-82d / 31 * sin(35d / 23 - 23 * t) - 165d / 82 * sin(31d / 20 - 22 * t) + - 109d / 20 * sin(36d / 23 - 12 * t) - 74d / 11 * sin(14d / 9 - 11 * t) + - 12d / 29 * sin(89d / 59 - 10 * t) - 8d / 17 * sin(19d / 13 - 7 * t) + - 211d / 35 * sin(14d / 9 - 6 * t) - 59d / 23 * sin(25d / 16 - 5 * t) + - 148d / 13 * sin(80d / 51 - 4 * t) - 465d / 13 * sin(36d / 23 - 2 * t) + + 2488d / 25 * sin(t + 11d / 7) + 95d / 26 * sin(3 * t + 49d / 31) + + 12d / 29 * sin(8 * t + 69d / 44) + 197d / 58 * sin(9 * t + 49d / 31) + + 26d / 33 * sin(13 * t + 79d / 17) + 67d / 9 * sin(14 * t + 62d / 39) + + 400d / 37 * sin(15 * t + 35d / 22) + 355d / 43 * sin(16 * t + 59d / 37) + + 19d / 20 * sin(17 * t + 70d / 43) + 5d / 16 * sin(18 * t + 55d / 32) + + 31d / 18 * sin(19 * t + 34d / 21) + 26d / 19 * sin(20 * t + 76d / 47) + + 6d / 19 * sin(21 * t + 119d / 26) + 6093d / 19) * theta(67 * pi - t) + * theta(t - 63 * pi) + + (-73d / 52 * sin(54d / 35 - 23 * t) - 54d / 25 * sin(58d / 37 - 19 * t) + - 73d / 20 * sin(14d / 9 - 17 * t) - 5d / 33 * sin(43d / 28 - 14 * t) + - 52d / 21 * sin(25d / 16 - 12 * t) + 4675d / 43 * sin(t + 96d / 61) + + 353d / 28 * sin(2 * t + 30d / 19) + 3799d / 200 * sin(3 * t + 41d / 26) + + 28d / 5 * sin(4 * t + 41d / 26) + 200d / 31 * sin(5 * t + 11d / 7) + + 41d / 28 * sin(6 * t + 41d / 26) + 21d / 29 * sin(7 * t + 31d / 20) + + 95d / 46 * sin(8 * t + 99d / 62) + 49d / 99 * sin(9 * t + 74d / 47) + + 17d / 22 * sin(10 * t + 211d / 45) + 77d / 34 * sin(11 * t + 27d / 17) + + 40d / 17 * sin(13 * t + 155d / 97) + 20d / 27 * sin(15 * t + 43d / 26) + + 47d / 16 * sin(16 * t + 59d / 37) + 149d / 37 * sin(18 * t + 43d / 27) + + 30d / 17 * sin(20 * t + 8d / 5) + 3d / 31 * sin(21 * t + 92d / 41) + + 16d / 23 * sin(22 * t + 45d / 29) + 28d / 39 * sin(24 * t + 17d / 11) - 9671d / 24) + * theta(63 * pi - t) * theta(t - 59 * pi) + + (-278d / 19 * sin(47d / 30 - 3 * t) - 181d / 29 * sin(58d / 37 - 2 * t) + - 2421d / 26 * sin(69d / 44 - t) + 9898d / 27) * theta(59 * pi - t) + * theta(t - 55 * pi) + + (7671d / 67 * sin(t + 107d / 68) + 355d / 36 * sin(2 * t + 11d / 7) + + 377d / 24 * sin(3 * t + 49d / 31) - 28766d / 63) * theta(55 * pi - t) + * theta(t - 51 * pi) + + (-1345d / 28 * sin(80d / 51 - 2 * t) - 359d / 25 * sin(113d / 72 - t) + + 259d / 15 * sin(3 * t + 11d / 7) + 5273d / 19) * theta(51 * pi - t) + * theta(t - 47 * pi) + + (-10399d / 100 * sin(91d / 58 - t) + 1514d / 33 * sin(2 * t + 85d / 54) - 24712d / 67) + * theta(47 * pi - t) * theta(t - 43 * pi) + + (-14d / 37 * sin(13d / 11 - 10 * t) + 300d / 41 * sin(t + 77d / 36) + + 102d / 23 * sin(2 * t + 73d / 110) + 259d / 30 * sin(3 * t + 11d / 4) + + 323d / 63 * sin(4 * t + 87d / 28) + 150d / 41 * sin(5 * t + 18d / 25) + + 26d / 37 * sin(6 * t + 69d / 19) + 16d / 35 * sin(7 * t + 19d / 25) + + 18d / 25 * sin(8 * t + 17d / 4) + 11d / 19 * sin(9 * t + 79d / 28) + + 5d / 19 * sin(11 * t + 19d / 10) + 13d / 31 * sin(12 * t + 95d / 21) + 8431d / 36) + * theta(43 * pi - t) * theta(t - 39 * pi) + + (-3d / 13 * sin(5d / 4 - 12 * t) - 21d / 29 * sin(59d / 38 - 6 * t) + - 70d / 11 * sin(26d / 19 - t) + 76d / 11 * sin(2 * t + 19d / 14) + + 162d / 29 * sin(3 * t + 203d / 45) + 439d / 73 * sin(4 * t + 124d / 27) + + 14d / 33 * sin(5 * t + 38d / 29) + 34d / 33 * sin(7 * t + 24d / 11) + + 39d / 46 * sin(8 * t + 94d / 21) + 11d / 40 * sin(9 * t + 13d / 15) + + 9d / 19 * sin(10 * t + 229d / 51) + 4d / 35 * sin(11 * t + 22d / 7) - 2147d / 6) + * theta(39 * pi - t) * theta(t - 35 * pi) + + (769d / 16 * sin(t + 20d / 17) + 49d / 31 * sin(2 * t + 84d / 23) + + 129d / 41 * sin(3 * t + 13d / 37) + 11433d / 47) * theta(35 * pi - t) + * theta(t - 31 * pi) + + (-14d / 17 * sin(22d / 23 - 4 * t) - 21d / 25 * sin(37d / 56 - 2 * t) + + 1493d / 31 * sin(t + 48d / 37) + 49d / 27 * sin(3 * t + 5d / 17) - 8077d / 23) + * theta(31 * pi - t) * theta(t - 27 * pi) + + (2099d / 23 * sin(t + 112d / 67) + 25d / 32 * sin(2 * t + 68d / 23) + + 129d / 16 * sin(3 * t + 50d / 27) + 31d / 34 * sin(4 * t + 373d / 112) + + 38d / 17 * sin(5 * t + 21d / 11) + 38d / 53 * sin(6 * t + 32d / 9) + + 25d / 28 * sin(7 * t + 83d / 46) + 10d / 19 * sin(8 * t + 134d / 35) + 10721d / 42) + * theta(27 * pi - t) * theta(t - 23 * pi) + + (3072d / 29 * sin(t + 29d / 19) + 9d / 8 * sin(2 * t + 256d / 73) + + 254d / 25 * sin(3 * t + 43d / 28) + 19d / 21 * sin(4 * t + 87d / 25) + + 95d / 26 * sin(5 * t + 81d / 52) + 21d / 32 * sin(6 * t + 23d / 6) + + 86d / 53 * sin(7 * t + 45d / 29) + 23d / 38 * sin(8 * t + 243d / 67) - 3827d / 11) + * theta(23 * pi - t) * theta(t - 19 * pi) + + (-25d / 17 * sin(36d / 25 - 6 * t) - 99d / 46 * sin(18d / 29 - 4 * t) + + 3796d / 29 * sin(t + 43d / 31) + 5d / 2 * sin(2 * t + 5d / 28) + + 227d / 35 * sin(3 * t + 26d / 21) + 47d / 20 * sin(5 * t + 43d / 39) + + 23d / 17 * sin(7 * t + 11d / 13) + 4572d / 17) * theta(19 * pi - t) + * theta(t - 15 * pi) + + (6353d / 37 * sin(t + 37d / 21) + 430d / 59 * sin(2 * t + 165d / 37) + + 537d / 43 * sin(3 * t + 78d / 31) + 133d / 25 * sin(4 * t + 143d / 32) + + 128d / 25 * sin(5 * t + 78d / 23) + 218d / 61 * sin(6 * t + 174d / 37) + + 51d / 22 * sin(7 * t + 34d / 9) - 12821d / 38) * theta(15 * pi - t) + * theta(t - 11 * pi) + + (-36d / 23 * sin(13d / 18 - 12 * t) - 77d / 36 * sin(17d / 30 - 10 * t) + - 82d / 31 * sin(17d / 24 - 8 * t) - 255d / 62 * sin(26d / 37 - 6 * t) + - 192d / 37 * sin(9d / 16 - 4 * t) - 199d / 40 * sin(21d / 47 - 2 * t) + + 5791d / 22 * sin(t + 63d / 41) + 1140d / 47 * sin(3 * t + 34d / 23) + + 92d / 13 * sin(5 * t + 29d / 21) + 63d / 22 * sin(7 * t + 19d / 17) + + 31d / 28 * sin(9 * t + 21d / 23) + 13d / 19 * sin(11 * t + 54d / 35) - 3874d / 61) + * theta(11 * pi - t) * theta(t - 7 * pi) + + (-186d / 29 * sin(3d / 2 - 6 * t) - 452d / 43 * sin(81d / 65 - 4 * t) + - 487d / 39 * sin(31d / 34 - 2 * t) + 3854d / 13 * sin(t + 102d / 73) + + 313d / 17 * sin(3 * t + 31d / 30) + 56d / 23 * sin(5 * t + 4d / 13) + + 46d / 33 * sin(7 * t + 33d / 13) + 110d / 27 * sin(8 * t + 57d / 13) + + 67d / 38 * sin(9 * t + 71d / 33) + 138d / 59 * sin(10 * t + 101d / 26) + + 11d / 8 * sin(11 * t + 46d / 25) + 20d / 23 * sin(12 * t + 103d / 29) - 605d / 13) + * theta(7 * pi - t) * theta(t - 3 * pi) + + (-320d / 43 * sin(21d / 34 - 6 * t) - 205d / 29 * sin(299d / 298 - 4 * t) + + 47179d / 69 * sin(t + 6d / 13) + 307d / 32 * sin(2 * t + 46d / 51) + + 1152d / 19 * sin(3 * t + 60d / 37) + 107d / 8 * sin(5 * t + 143d / 37) + + 2626d / 175 * sin(7 * t + 45d / 26) + 131d / 22 * sin(8 * t + 143d / 40) + + 296d / 47 * sin(9 * t + 500d / 499) + 16d / 7 * sin(10 * t + 93d / 25) - 4117d / 31) + * theta(3 * pi - t) * theta(t + pi)) * theta(Math.Sqrt(Math.Sign(sin(t / 2)))); + Func yt = + t => + ((-52d / 5 * sin(54d / 37 - 34 * t) - 179d / 56 * sin(46d / 33 - 31 * t) + - 513d / 28 * sin(59d / 39 - 25 * t) - 316d / 105 * sin(43d / 28 - 22 * t) + - 259d / 16 * sin(102d / 65 - 17 * t) - 26239d / 64 * sin(36d / 23 - 3 * t) + - 18953d / 51 * sin(58d / 37 - t) + 11283d / 29 * sin(2 * t + 30d / 19) + + 29123d / 35 * sin(4 * t + 49d / 31) + 6877d / 14 * sin(5 * t + 65d / 41) + + 117d / 50 * sin(6 * t + 103d / 51) + 587d / 13 * sin(7 * t + 164d / 35) + + 102d / 13 * sin(8 * t + 236d / 51) + 975d / 14 * sin(9 * t + 101d / 63) + + 122d / 41 * sin(10 * t + 79d / 44) + 1900d / 139 * sin(11 * t + 117d / 25) + + 597d / 22 * sin(12 * t + 31d / 19) + 1219d / 39 * sin(13 * t + 8d / 5) + + 552d / 13 * sin(14 * t + 35d / 22) + 621d / 26 * sin(15 * t + 31d / 19) + + 705d / 28 * sin(16 * t + 212d / 45) + 579d / 11 * sin(18 * t + 34d / 21) + + 19d / 27 * sin(19 * t + 190d / 43) + 15d / 29 * sin(20 * t + 89d / 20) + + 497d / 23 * sin(21 * t + 128d / 77) + 205d / 51 * sin(23 * t + 57d / 34) + + 317d / 35 * sin(24 * t + 68d / 39) + 17d / 4 * sin(26 * t + 202d / 43) + + 927d / 34 * sin(27 * t + 33d / 20) + 31d / 23 * sin(28 * t + 154d / 123) + + 37d / 6 * sin(29 * t + 28d / 17) + 159d / 19 * sin(30 * t + 22d / 13) + + 87d / 23 * sin(32 * t + 82d / 49) + 57d / 28 * sin(33 * t + 103d / 52) + + 77d / 29 * sin(35 * t + 116d / 25) + 489d / 41 * sin(36 * t + 49d / 29) + + 61d / 30 * sin(37 * t + 62d / 39) + 313d / 47 * sin(38 * t + 69d / 40) + + 36d / 11 * sin(39 * t + 41d / 23) + 90d / 91 * sin(40 * t + 7d / 4) + + 47d / 19 * sin(41 * t + 101d / 63) - 8810d / 27) * theta(119 * pi - t) + * theta(t - 115 * pi) + + (-91d / 46 * sin(11d / 8 - 62 * t) - 59d / 28 * sin(39d / 34 - 61 * t) + - 11d / 2 * sin(89d / 67 - 60 * t) - 15d / 8 * sin(32d / 35 - 59 * t) + - 53d / 22 * sin(48d / 35 - 58 * t) - 175d / 176 * sin(13d / 12 - 54 * t) + - 71d / 15 * sin(30d / 23 - 53 * t) - 166d / 27 * sin(25d / 18 - 52 * t) + - 48d / 29 * sin(20d / 31 - 51 * t) - 547d / 114 * sin(43d / 31 - 50 * t) + - 271d / 41 * sin(51d / 37 - 46 * t) - 141d / 20 * sin(42d / 31 - 45 * t) + - 129d / 13 * sin(37d / 26 - 44 * t) - 164d / 23 * sin(37d / 26 - 41 * t) + - 451d / 52 * sin(31d / 21 - 40 * t) - 27d / 22 * sin(63d / 44 - 38 * t) + - 83d / 7 * sin(35d / 24 - 36 * t) - 874d / 93 * sin(7d / 5 - 35 * t) + - 117d / 22 * sin(22d / 17 - 34 * t) - 911d / 69 * sin(3d / 2 - 32 * t) + - 109d / 37 * sin(27d / 19 - 31 * t) - 31d / 13 * sin(16d / 19 - 27 * t) + - 383d / 10 * sin(64d / 43 - 26 * t) - 455d / 19 * sin(31d / 21 - 24 * t) + - 764d / 17 * sin(58d / 39 - 18 * t) - 5417d / 48 * sin(74d / 49 - 17 * t) + - 1557d / 35 * sin(80d / 53 - 16 * t) - 3366d / 25 * sin(71d / 46 - 12 * t) + - 2267d / 100 * sin(91d / 61 - 11 * t) - 1523d / 27 * sin(239d / 159 - 10 * t) + - 7929d / 44 * sin(36d / 23 - 7 * t) + 32716d / 55 * sin(t + 146d / 31) + + 26497d / 40 * sin(2 * t + 30d / 19) + 28971d / 35 * sin(3 * t + 19d / 12) + + 12399d / 44 * sin(4 * t + 117d / 73) + 3783d / 29 * sin(5 * t + 145d / 31) + + 21737d / 40 * sin(6 * t + 46d / 29) + 132d / 7 * sin(8 * t + 23d / 14) + + 887d / 32 * sin(9 * t + 25d / 16) + 963d / 14 * sin(13 * t + 67d / 41) + + 972d / 11 * sin(14 * t + 47d / 29) + 5575d / 77 * sin(15 * t + 53d / 33) + + 382d / 25 * sin(19 * t + 47d / 32) + 855d / 44 * sin(20 * t + 28d / 17) + + 701d / 42 * sin(21 * t + 33d / 20) + 109d / 23 * sin(22 * t + 14d / 3) + + 197d / 38 * sin(23 * t + 43d / 29) + 118d / 37 * sin(25 * t + 37d / 38) + + 272d / 31 * sin(28 * t + 44d / 27) + 5d / 23 * sin(29 * t + 25d / 26) + + 195d / 28 * sin(30 * t + 47d / 28) + 185d / 24 * sin(33 * t + 57d / 37) + + 103d / 13 * sin(37 * t + 46d / 29) + 43d / 9 * sin(39 * t + 41d / 26) + + 257d / 32 * sin(42 * t + 51d / 32) + 33d / 13 * sin(43 * t + 41d / 30) + + 67d / 15 * sin(47 * t + 31d / 19) + 39d / 14 * sin(48 * t + 44d / 25) + + 88d / 31 * sin(49 * t + 30d / 19) + 113d / 68 * sin(55 * t + 103d / 69) + + 1d / 54 * sin(56 * t + 197d / 58) + 79d / 24 * sin(57 * t + 167d / 100) + 287d / 29) + * theta(115 * pi - t) * theta(t - 111 * pi) + + (-8d / 25 * sin(17d / 31 - 90 * t) - 144d / 37 * sin(29d / 19 - 89 * t) + - 102d / 47 * sin(37d / 24 - 88 * t) - 74d / 43 * sin(24d / 17 - 87 * t) + - 95d / 17 * sin(25d / 16 - 49 * t) - 137d / 27 * sin(16d / 11 - 27 * t) + + 21445d / 52 * sin(t + 69d / 44) + 24223d / 27 * sin(2 * t + 113d / 24) + + 23911d / 28 * sin(3 * t + 146d / 31) + 2675d / 8 * sin(4 * t + 64d / 41) + + 5772d / 19 * sin(5 * t + 36d / 23) + 3258d / 17 * sin(6 * t + 11d / 7) + + 5245d / 37 * sin(7 * t + 174d / 37) + 355d / 16 * sin(8 * t + 117d / 73) + + 225d / 8 * sin(9 * t + 88d / 19) + 3255d / 26 * sin(10 * t + 11d / 7) + + 1137d / 19 * sin(11 * t + 39d / 25) + 1310d / 21 * sin(12 * t + 8d / 5) + + 943d / 21 * sin(13 * t + 29d / 18) + 9679d / 81 * sin(14 * t + 80d / 51) + + 113d / 20 * sin(15 * t + 47d / 28) + 1342d / 47 * sin(16 * t + 86d / 53) + + 3679d / 84 * sin(17 * t + 55d / 36) + 353d / 20 * sin(18 * t + 50d / 11) + + 939d / 50 * sin(19 * t + 201d / 43) + 4789d / 82 * sin(20 * t + 48d / 31) + + 2649d / 85 * sin(21 * t + 303d / 65) + 1753d / 59 * sin(22 * t + 36d / 23) + + 268d / 29 * sin(23 * t + 58d / 39) + 55d / 16 * sin(24 * t + 82d / 43) + + 228d / 37 * sin(25 * t + 353d / 235) + 8d / 25 * sin(26 * t + 49d / 31) + + 422d / 25 * sin(28 * t + 93d / 20) + 211d / 21 * sin(29 * t + 38d / 27) + + 60d / 41 * sin(30 * t + 131d / 29) + 162d / 11 * sin(31 * t + 65d / 14) + + 2489d / 63 * sin(32 * t + 35d / 23) + 688d / 27 * sin(33 * t + 129d / 28) + + 1447d / 62 * sin(34 * t + 55d / 36) + 233d / 26 * sin(35 * t + 85d / 57) + + 259d / 26 * sin(36 * t + 95d / 21) + 149d / 10 * sin(37 * t + 25d / 17) + + 235d / 57 * sin(38 * t + 50d / 11) + 185d / 38 * sin(39 * t + 183d / 41) + + 125d / 13 * sin(40 * t + 68d / 45) + 223d / 31 * sin(41 * t + 39d / 25) + + 61d / 12 * sin(42 * t + 355d / 79) + 1262d / 99 * sin(43 * t + 160d / 107) + + 309d / 40 * sin(44 * t + 41d / 26) + 307d / 38 * sin(45 * t + 221d / 48) + + 49d / 5 * sin(46 * t + 137d / 91) + 193d / 31 * sin(47 * t + 190d / 41) + + 77d / 54 * sin(48 * t + 95d / 63) + 20d / 33 * sin(50 * t + 148d / 51) + + 256d / 47 * sin(51 * t + 53d / 39) + 133d / 37 * sin(52 * t + 92d / 21) + + 19d / 7 * sin(53 * t + 121d / 81) + 39d / 4 * sin(54 * t + 71d / 47) + + 341d / 85 * sin(55 * t + 113d / 25) + 71d / 31 * sin(56 * t + 115d / 67) + + 31d / 10 * sin(57 * t + 36d / 25) + 11d / 5 * sin(58 * t + 30d / 7) + + 62d / 23 * sin(59 * t + 33d / 23) + 40d / 33 * sin(60 * t + 67d / 36) + + 13d / 40 * sin(61 * t + 32d / 19) + 47d / 6 * sin(62 * t + 80d / 53) + + 48d / 11 * sin(63 * t + 73d / 16) + 301d / 47 * sin(64 * t + 56d / 37) + + 361d / 120 * sin(65 * t + 191d / 41) + 59d / 31 * sin(66 * t + 83d / 52) + + 132d / 25 * sin(67 * t + 117d / 25) + 37d / 13 * sin(68 * t + 4d / 3) + + 167d / 35 * sin(69 * t + 183d / 40) + 67d / 41 * sin(70 * t + 4d / 3) + + 103d / 42 * sin(71 * t + 49d / 34) + 199d / 71 * sin(72 * t + 101d / 23) + + 200d / 31 * sin(73 * t + 77d / 53) + 81d / 58 * sin(74 * t + 169d / 38) + + 17d / 21 * sin(75 * t + 83d / 20) + 27d / 38 * sin(76 * t + 79d / 59) + + 59d / 29 * sin(77 * t + 47d / 33) + 175d / 44 * sin(78 * t + 114d / 25) + + 54d / 19 * sin(79 * t + 63d / 43) + 19d / 27 * sin(80 * t + 61d / 27) + + 149d / 26 * sin(81 * t + 16d / 11) + 68d / 29 * sin(82 * t + 102d / 25) + + 313d / 68 * sin(83 * t + 54d / 35) + 147d / 23 * sin(84 * t + 47d / 32) + + 73d / 12 * sin(85 * t + 107d / 24) + 191d / 51 * sin(86 * t + 38d / 27) + + 37d / 28 * sin(91 * t + 173d / 37) + 70d / 43 * sin(92 * t + 35d / 23) + + 44d / 35 * sin(93 * t + 53d / 13) + 164d / 35 * sin(94 * t + 107d / 67) + + 141d / 34 * sin(95 * t + 37d / 25) + 19d / 12 * sin(96 * t + 83d / 21) + + 22d / 23 * sin(97 * t + 47d / 31) + 152d / 39 * sin(98 * t + 60d / 43) + + 123d / 28 * sin(99 * t + 132d / 29) - 15137d / 22) * theta(111 * pi - t) + * theta(t - 107 * pi) + + (-43d / 40 * sin(102d / 65 - 45 * t) - 74d / 41 * sin(25d / 27 - 35 * t) + - 47d / 19 * sin(15d / 16 - 34 * t) - 67d / 32 * sin(21d / 25 - 33 * t) + - 161d / 39 * sin(27d / 20 - 32 * t) - 12d / 23 * sin(17d / 12 - 29 * t) + - 29d / 57 * sin(45d / 37 - 27 * t) - 19d / 16 * sin(117d / 88 - 25 * t) + - 11d / 36 * sin(15d / 22 - 24 * t) - 11d / 30 * sin(33d / 82 - 23 * t) + - 43d / 57 * sin(14d / 17 - 22 * t) - 87d / 65 * sin(49d / 41 - 21 * t) + - 50d / 21 * sin(64d / 47 - 20 * t) - 17d / 59 * sin(56d / 55 - 6 * t) + - 56d / 61 * sin(77d / 58 - 5 * t) + 127d / 28 * sin(t + 149d / 32) + + 15d / 2 * sin(2 * t + 21d / 13) + 35d / 29 * sin(3 * t + 49d / 29) + + 1d / 9 * sin(4 * t + 51d / 43) + 37d / 38 * sin(7 * t + 19d / 12) + + 18d / 31 * sin(8 * t + 57d / 13) + 38d / 31 * sin(9 * t + 55d / 12) + + 7d / 10 * sin(10 * t + 74d / 45) + 9d / 34 * sin(11 * t + 69d / 34) + + 39d / 19 * sin(12 * t + 41d / 26) + 89d / 26 * sin(13 * t + 67d / 42) + + 63d / 26 * sin(14 * t + 107d / 23) + 119d / 16 * sin(15 * t + 23d / 5) + + 311d / 18 * sin(16 * t + 56d / 33) + 1929d / 386 * sin(17 * t + 99d / 50) + + 79d / 41 * sin(18 * t + 64d / 29) + 34d / 41 * sin(19 * t + 67d / 35) + + 16d / 41 * sin(26 * t + 49d / 33) + 1d / 34 * sin(28 * t + 5d / 14) + + 36d / 43 * sin(30 * t + 193d / 41) + 173d / 42 * sin(31 * t + 30d / 19) + + 15d / 19 * sin(36 * t + 31d / 28) + 2d / 19 * sin(37 * t + 87d / 43) + + 22d / 39 * sin(38 * t + 33d / 14) + 13d / 23 * sin(39 * t + 19d / 6) + + 21d / 19 * sin(40 * t + 1641d / 820) + 29d / 28 * sin(41 * t + 172d / 39) + + 39d / 34 * sin(42 * t + 58d / 31) + 16d / 29 * sin(43 * t + 50d / 23) + + 24d / 25 * sin(44 * t + 41d / 23) + 17d / 23 * sin(46 * t + 289d / 62) + + 37d / 25 * sin(47 * t + 30d / 17) + 17d / 29 * sin(48 * t + 239d / 52) + + 29d / 73 * sin(49 * t + 41d / 26) - 8044d / 23) * theta(107 * pi - t) + * theta(t - 103 * pi) + + (-33d / 29 * sin(7d / 6 - 53 * t) - 67d / 44 * sin(62d / 45 - 51 * t) + - 32d / 65 * sin(1d / 14 - 50 * t) - 151d / 49 * sin(54d / 41 - 49 * t) + - 63d / 38 * sin(29d / 23 - 47 * t) - 59d / 103 * sin(14d / 23 - 46 * t) + - 11d / 30 * sin(8d / 23 - 45 * t) - 151d / 32 * sin(99d / 79 - 44 * t) + - 53d / 26 * sin(45d / 38 - 43 * t) - 67d / 27 * sin(38d / 29 - 36 * t) + - 113d / 32 * sin(39d / 29 - 35 * t) - 182d / 51 * sin(81d / 58 - 33 * t) + - 391d / 65 * sin(33d / 23 - 29 * t) - 48d / 13 * sin(31d / 20 - 25 * t) + - 59d / 32 * sin(24d / 17 - 19 * t) - 90d / 91 * sin(41d / 33 - 18 * t) + - 863d / 54 * sin(35d / 24 - 17 * t) - 384d / 43 * sin(73d / 51 - 16 * t) + - 149d / 26 * sin(19d / 13 - 13 * t) - 90d / 19 * sin(65d / 43 - 12 * t) + + 10d / 29 * sin(t + 47d / 32) + 15d / 17 * sin(2 * t + 77d / 45) + + 300d / 37 * sin(3 * t + 62d / 39) + 4d / 13 * sin(4 * t + 8d / 5) + + 7d / 29 * sin(5 * t + 109d / 25) + 46d / 27 * sin(6 * t + 49d / 30) + + 39d / 23 * sin(7 * t + 30d / 19) + 64d / 47 * sin(8 * t + 72d / 43) + + 19d / 20 * sin(9 * t + 63d / 37) + 14d / 5 * sin(10 * t + 41d / 25) + + 37d / 14 * sin(11 * t + 27d / 16) + 207d / 28 * sin(14 * t + 248d / 149) + + 288d / 25 * sin(15 * t + 58d / 35) + 123d / 52 * sin(20 * t + 85d / 46) + + 194d / 13 * sin(21 * t + 17d / 10) + 64d / 13 * sin(22 * t + 103d / 22) + + 335d / 27 * sin(23 * t + 31d / 18) + 103d / 18 * sin(24 * t + 13d / 7) + + 83d / 20 * sin(26 * t + 117d / 67) + 243d / 52 * sin(27 * t + 36d / 19) + + 1907d / 477 * sin(28 * t + 125d / 73) + 73d / 30 * sin(30 * t + 182d / 109) + + 182d / 109 * sin(31 * t + 43d / 23) + 53d / 23 * sin(32 * t + 147d / 92) + + 21d / 43 * sin(34 * t + 145d / 144) + 20d / 17 * sin(37 * t + 29d / 14) + + 110d / 27 * sin(38 * t + 79d / 44) + 22d / 27 * sin(39 * t + 74d / 17) + + 99d / 37 * sin(40 * t + 52d / 29) + 36d / 25 * sin(41 * t + 255d / 128) + + 11d / 15 * sin(42 * t + 124d / 69) + 31d / 17 * sin(48 * t + 67d / 41) + + 15d / 14 * sin(52 * t + 73d / 47) - 10105d / 36) * theta(103 * pi - t) + * theta(t - 99 * pi) + + (3683d / 48 * sin(t + 74d / 47) + 41d / 26 * sin(2 * t + 103d / 22) + + 149d / 17 * sin(3 * t + 85d / 54) + 6d / 13 * sin(4 * t + 51d / 11) + + 112d / 43 * sin(5 * t + 11d / 7) + 17294d / 53) * theta(99 * pi - t) + * theta(t - 95 * pi) + + (-19d / 40 * sin(29d / 20 - 11 * t) - 289d / 38 * sin(36d / 23 - 9 * t) + + 802d / 33 * sin(t + 179d / 38) + 3002d / 35 * sin(2 * t + 85d / 54) + + 159d / 41 * sin(3 * t + 61d / 39) + 1321d / 44 * sin(4 * t + 52d / 33) + + 131d / 22 * sin(5 * t + 113d / 24) + 52d / 35 * sin(6 * t + 69d / 44) + + 321d / 37 * sin(7 * t + 36d / 23) + 789d / 158 * sin(8 * t + 36d / 23) + + 56d / 113 * sin(10 * t + 50d / 33) + 237d / 118 * sin(12 * t + 39d / 25) - 703d / 42) + * theta(95 * pi - t) * theta(t - 91 * pi) + + (-121d / 68 * sin(25d / 16 - 4 * t) - 55d / 27 * sin(81d / 52 - 3 * t) + - 613d / 68 * sin(25d / 16 - 2 * t) - 505d / 19 * sin(47d / 30 - t) + 16067d / 23) + * theta(91 * pi - t) * theta(t - 87 * pi) + + (-83d / 19 * sin(47d / 30 - 5 * t) + 56d / 25 * sin(t + 193d / 41) + + 35d / 29 * sin(2 * t + 146d / 31) + 127d / 25 * sin(3 * t + 74d / 47) + + 143d / 35 * sin(4 * t + 63d / 40) + 33d / 50 * sin(6 * t + 107d / 68) + 17679d / 28) + * theta(87 * pi - t) * theta(t - 83 * pi) + + (-35d / 32 * sin(31d / 20 - 11 * t) - 55d / 48 * sin(61d / 39 - 9 * t) + - 30d / 17 * sin(50d / 33 - 6 * t) - 247d / 17 * sin(64d / 41 - 5 * t) + - 471d / 35 * sin(58d / 37 - 3 * t) + 405d / 23 * sin(t + 41d / 26) + + 829d / 69 * sin(2 * t + 11d / 7) + 279d / 17 * sin(4 * t + 30d / 19) + + 185d / 27 * sin(7 * t + 93d / 58) + 92d / 25 * sin(8 * t + 43d / 27) + + 1d / 17 * sin(10 * t + 56d / 31) + 64d / 35 * sin(12 * t + 37d / 23) + 3306d / 17) + * theta(83 * pi - t) * theta(t - 79 * pi) + + (-143d / 24 * sin(36d / 23 - t) + 9d / 22 * sin(2 * t + 47d / 10) + + 31d / 42 * sin(3 * t + 28d / 17) + 1287d / 103 * sin(4 * t + 30d / 19) + + 626d / 51 * sin(5 * t + 41d / 26) + 173d / 31 * sin(6 * t + 113d / 24) + + 138d / 19 * sin(7 * t + 19d / 12) + 15d / 4 * sin(8 * t + 27d / 17) + + 39d / 34 * sin(9 * t + 8d / 5) + 11d / 18 * sin(10 * t + 202d / 43) + + 23d / 25 * sin(11 * t + 71d / 44) + 133d / 34 * sin(12 * t + 27d / 17) + 19064d / 89) + * theta(79 * pi - t) * theta(t - 75 * pi) + + (-69d / 38 * sin(44d / 29 - 19 * t) - 49d / 17 * sin(119d / 79 - 16 * t) + - 65d / 23 * sin(83d / 55 - 11 * t) - 149d / 35 * sin(32d / 21 - 10 * t) + - 311d / 56 * sin(14d / 9 - 8 * t) - 83d / 40 * sin(20d / 13 - 7 * t) + - 35d / 6 * sin(57d / 37 - 6 * t) - 55d / 19 * sin(57d / 37 - 5 * t) + - 93d / 19 * sin(39d / 25 - 4 * t) - 87d / 8 * sin(39d / 25 - 3 * t) + - 517d / 30 * sin(25d / 16 - 2 * t) + 387d / 28 * sin(t + 91d / 58) + + 68d / 33 * sin(9 * t + 27d / 17) + 67d / 34 * sin(12 * t + 76d / 47) + + 13d / 20 * sin(13 * t + 45d / 26) + 2d / 25 * sin(14 * t + 127d / 28) + + 131d / 56 * sin(15 * t + 61d / 38) + 62d / 29 * sin(17 * t + 188d / 113) + + 26d / 37 * sin(18 * t + 77d / 46) + 8d / 33 * sin(20 * t + 43d / 38) + 5327d / 11) + * theta(75 * pi - t) * theta(t - 71 * pi) + + (-21d / 23 * sin(98d / 65 - 16 * t) - 22d / 23 * sin(47d / 30 - 9 * t) + - 13d / 19 * sin(25d / 16 - 7 * t) + 28d / 57 * sin(t + 87d / 56) + + 1265d / 47 * sin(2 * t + 179d / 38) + 223d / 20 * sin(3 * t + 11d / 7) + + 227d / 19 * sin(4 * t + 179d / 38) + 45d / 22 * sin(5 * t + 11d / 7) + + 188d / 53 * sin(6 * t + 127d / 27) + 116d / 35 * sin(8 * t + 179d / 38) + + 19d / 12 * sin(10 * t + 27d / 17) + 8d / 11 * sin(11 * t + 19d / 12) + + 29d / 13 * sin(12 * t + 179d / 38) + 69d / 43 * sin(13 * t + 25d / 16) + + 277d / 278 * sin(14 * t + 107d / 23) + 31d / 27 * sin(15 * t + 127d / 27) + + 63d / 22 * sin(17 * t + 155d / 33) + 13d / 19 * sin(18 * t + 43d / 27) + + 107d / 89 * sin(19 * t + 103d / 22) + 13d / 12 * sin(20 * t + 61d / 13) + + 22d / 17 * sin(21 * t + 39d / 25) + 8121d / 16) * theta(71 * pi - t) + * theta(t - 67 * pi) + + (-89d / 18 * sin(68d / 45 - 23 * t) - 27d / 17 * sin(26d / 17 - 20 * t) + - 109d / 39 * sin(73d / 47 - 18 * t) - 142d / 57 * sin(26d / 17 - 17 * t) + - 146d / 27 * sin(45d / 29 - 14 * t) - 43d / 9 * sin(31d / 20 - 13 * t) + - 164d / 33 * sin(95d / 61 - 12 * t) - 91d / 34 * sin(43d / 28 - 11 * t) + - 30d / 19 * sin(29d / 19 - 9 * t) - 55d / 17 * sin(59d / 38 - 8 * t) + - 183d / 29 * sin(64d / 41 - 6 * t) - 137d / 25 * sin(53d / 34 - 5 * t) + - 124d / 19 * sin(36d / 23 - 4 * t) - 655d / 44 * sin(47d / 30 - 2 * t) + - 472d / 13 * sin(58d / 37 - t) + 43d / 57 * sin(3 * t + 70d / 43) + + 41d / 12 * sin(7 * t + 85d / 54) + 29d / 115 * sin(10 * t + 38d / 23) + + 27d / 7 * sin(15 * t + 19d / 12) + 21d / 20 * sin(16 * t + 36d / 23) + + 26d / 51 * sin(19 * t + 36d / 23) + 2d / 31 * sin(21 * t + 67d / 42) + + 59d / 26 * sin(22 * t + 31d / 19) + 8662d / 25) * theta(67 * pi - t) + * theta(t - 63 * pi) + + (-40d / 27 * sin(86d / 57 - 24 * t) - 5d / 33 * sin(4d / 15 - 23 * t) + - 107d / 27 * sin(57d / 37 - 22 * t) - 163d / 12 * sin(37d / 24 - 18 * t) + - 80d / 43 * sin(73d / 47 - 15 * t) - 245d / 57 * sin(31d / 20 - 13 * t) + - 22d / 29 * sin(43d / 28 - 10 * t) - 99d / 20 * sin(59d / 38 - 8 * t) + - 18d / 11 * sin(59d / 38 - 7 * t) - 35d / 16 * sin(58d / 37 - 6 * t) + - 81d / 161 * sin(41d / 28 - 3 * t) - 271d / 13 * sin(58d / 37 - 2 * t) + + 148d / 7 * sin(t + 85d / 54) + 98d / 25 * sin(4 * t + 146d / 31) + + 67d / 24 * sin(5 * t + 30d / 19) + 8d / 25 * sin(9 * t + 179d / 38) + + 5d / 9 * sin(11 * t + 131d / 28) + 46d / 51 * sin(12 * t + 32d / 21) + + 108d / 31 * sin(14 * t + 69d / 43) + 149d / 29 * sin(16 * t + 45d / 28) + + 59d / 15 * sin(17 * t + 46d / 29) + 134d / 21 * sin(19 * t + 125d / 78) + + 158d / 27 * sin(20 * t + 44d / 27) + 35d / 29 * sin(21 * t + 31d / 19) + 9838d / 25) + * theta(63 * pi - t) * theta(t - 59 * pi) + + (-385d / 16 * sin(47d / 30 - 3 * t) - 21082d / 91 * sin(69d / 44 - t) + + 21d / 13 * sin(2 * t + 8d / 5) - 31214d / 91) * theta(59 * pi - t) + * theta(t - 55 * pi) + + (-860d / 41 * sin(39d / 25 - 3 * t) - 5675d / 26 * sin(69d / 44 - t) + + 265d / 43 * sin(2 * t + 46d / 29) - 33516d / 73) * theta(55 * pi - t) + * theta(t - 51 * pi) + + (-621d / 28 * sin(36d / 23 - 3 * t) - 244d / 31 * sin(91d / 58 - 2 * t) + - 4739d / 19 * sin(102d / 65 - t) - 20129d / 76) * theta(51 * pi - t) + * theta(t - 47 * pi) + + (-504d / 31 * sin(25d / 16 - 2 * t) - 6167d / 31 * sin(80d / 51 - t) - 4810d / 29) + * theta(47 * pi - t) * theta(t - 43 * pi) + + (-1d / 14 * sin(9d / 11 - 12 * t) - 21d / 41 * sin(29d / 25 - 11 * t) + - 7d / 10 * sin(48d / 35 - 9 * t) + 157d / 25 * sin(t + 118d / 41) + + 92d / 41 * sin(2 * t + 110d / 39) + 571d / 84 * sin(3 * t + 101d / 23) + + 146d / 37 * sin(4 * t + 211d / 48) + 71d / 34 * sin(5 * t + 45d / 26) + + 7d / 31 * sin(6 * t + 4d / 3) + 7d / 13 * sin(7 * t + 44d / 25) + + 9d / 11 * sin(8 * t + 37d / 53) + 12d / 29 * sin(10 * t + 31d / 18) + 16173d / 50) + * theta(43 * pi - t) * theta(t - 39 * pi) + + (-25d / 29 * sin(1d / 110 - 10 * t) - 81d / 71 * sin(11d / 29 - 6 * t) + - 101d / 19 * sin(16d / 49 - 4 * t) - 81d / 19 * sin(11d / 43 - 3 * t) + + 167d / 43 * sin(t + 175d / 41) + 181d / 37 * sin(2 * t + 58d / 17) + + 6d / 5 * sin(5 * t + 61d / 14) + 25d / 22 * sin(7 * t + 3) + + 37d / 30 * sin(8 * t + 1d / 25) + 31d / 40 * sin(9 * t + 61d / 22) + + 9d / 35 * sin(11 * t + 103d / 30) + 14d / 19 * sin(12 * t + 1d / 10) + 8453d / 25) + * theta(39 * pi - t) * theta(t - 35 * pi) + + (-151d / 36 * sin(17d / 23 - 3 * t) - 331d / 12 * sin(8d / 31 - t) + + 184d / 47 * sin(2 * t + 160d / 39) + 324) * theta(35 * pi - t) * theta(t - 31 * pi) + + (-50d / 19 * sin(6d / 17 - 3 * t) - 1333d / 36 * sin(1d / 5 - t) + + 23d / 19 * sin(2 * t + 23d / 9) + 29d / 36 * sin(4 * t + 67d / 24) + 13271d / 39) + * theta(31 * pi - t) * theta(t - 27 * pi) + + (-119d / 22 * sin(27d / 19 - 2 * t) + 1265d / 36 * sin(t + 4d / 29) + + 98d / 15 * sin(3 * t + 3d / 5) + 89d / 48 * sin(4 * t + 142d / 31) + + 55d / 19 * sin(5 * t + 32d / 37) + 16d / 17 * sin(6 * t + 89d / 25) + + 21d / 16 * sin(7 * t + 23d / 40) + 8d / 13 * sin(8 * t + 37d / 12) + 10562d / 33) + * theta(27 * pi - t) * theta(t - 23 * pi) + + (-71d / 46 * sin(1d / 11 - 7 * t) - 115d / 64 * sin(5d / 19 - 5 * t) + - 11d / 28 * sin(16d / 25 - 4 * t) - 44d / 17 * sin(33d / 43 - 3 * t) + - 1265d / 29 * sin(2d / 13 - t) + 59d / 16 * sin(2 * t + 211d / 53) + + 12d / 25 * sin(6 * t + 57d / 20) + 26d / 51 * sin(8 * t + 65d / 17) + 11467d / 34) + * theta(23 * pi - t) * theta(t - 19 * pi) + + (-23d / 41 * sin(81d / 58 - 5 * t) + 4367d / 48 * sin(t + 111d / 38) + + 49d / 16 * sin(2 * t + 173d / 39) + 134d / 45 * sin(3 * t + 70d / 29) + + 64d / 37 * sin(4 * t + 41d / 17) + 21d / 46 * sin(6 * t + 29d / 13) + + 10d / 19 * sin(7 * t + 53d / 37) + 10855d / 34) * theta(19 * pi - t) + * theta(t - 15 * pi) + + (-127d / 13 * sin(7d / 18 - 3 * t) + 2713d / 29 * sin(t + 2d / 37) + + 101d / 13 * sin(2 * t + 203d / 45) + 89d / 34 * sin(4 * t + 73d / 17) + + 26d / 15 * sin(5 * t + 26d / 41) + 2d / 9 * sin(6 * t + 177d / 50) + + 35d / 71 * sin(7 * t + 66d / 31) + 10805d / 33) * theta(15 * pi - t) + * theta(t - 11 * pi) + + (-20d / 23 * sin(38d / 29 - 11 * t) - 31d / 18 * sin(46d / 37 - 9 * t) + - 497d / 108 * sin(9d / 16 - 5 * t) - 2375d / 26 * sin(3d / 29 - t) + + 970d / 41 * sin(2 * t + 35d / 32) + 1011d / 92 * sin(3 * t + 7d / 38) + + 131d / 27 * sin(4 * t + 91d / 90) + 24d / 71 * sin(6 * t + 34d / 37) + + 90d / 29 * sin(7 * t + 14d / 23) + 21d / 16 * sin(8 * t + 25d / 12) + + 21d / 38 * sin(10 * t + 89d / 19) + 7d / 27 * sin(12 * t + 68d / 15) - 10719d / 37) + * theta(11 * pi - t) * theta(t - 7 * pi) + + (-11d / 37 * sin(4d / 7 - 6 * t) - 299d / 56 * sin(24d / 19 - 5 * t) + - 499d / 38 * sin(5d / 44 - 3 * t) - 6150d / 37 * sin(12d / 59 - t) + + 1019d / 38 * sin(2 * t + 28d / 37) + 183d / 53 * sin(4 * t + 85d / 71) + + 95d / 43 * sin(7 * t + 169d / 38) + 29d / 27 * sin(8 * t + 111d / 40) + + 21d / 22 * sin(9 * t + 16d / 29) + 194d / 83 * sin(10 * t + 164d / 57) + + 31d / 30 * sin(11 * t + 1d / 53) + 17d / 31 * sin(12 * t + 77d / 29) - 24819d / 82) + * theta(7 * pi - t) * theta(t - 3 * pi) + + (-14d / 13 * sin(4d / 45 - 10 * t) - 229d / 26 * sin(16d / 23 - 7 * t) + - 222d / 17 * sin(28d / 23 - 5 * t) - 851d / 29 * sin(10d / 51 - 3 * t) + - 12070d / 13 * sin(12d / 11 - t) + 270d / 31 * sin(2 * t + 62d / 15) + + 53d / 7 * sin(4 * t + 400d / 87) + 59d / 10 * sin(6 * t + 12d / 13) + + 141d / 31 * sin(8 * t + 30d / 17) + 79d / 40 * sin(9 * t + 121d / 26) + 5838d / 29) + * theta(3 * pi - t) * theta(t + pi)) * theta(Math.Sqrt(Math.Sign(sin(t / 2)))); + + var model = new PlotModel { Title = "Angelina Jolie curve", PlotType = PlotType.Cartesian }; + var fs = new FunctionSeries(xt, yt, 0, Math.PI * 120, 10000); + model.Series.Add(fs); + + // Insert breaks at discontinuities + // TODO: this should be improved... + for (int i = 0; i + 1 < fs.Points.Count; i++) + { + var dx = fs.Points[i + 1].X - fs.Points[i].X; + var dy = fs.Points[i + 1].Y - fs.Points[i].Y; + if ((dx * dx) + (dy * dy) > 100000) + { + fs.Points.Insert(i + 1, new DataPoint(double.NaN, double.NaN)); + i++; + } + } + + return model; + } + + /// + /// Gets the stream for the specified embedded resource. + /// + /// The name of the resource. + /// A stream. + private static Stream GetResourceStream(string name) + { + return typeof(MiscExamples).GetTypeInfo().Assembly.GetManifestResourceStream("ExampleLibrary.Resources." + name); + } + + /// + /// Renders the Mandelbrot set as an image inside the current plot area. + /// + public class MandelbrotSetSeries : XYAxisSeries + { + /// + /// Initializes a new instance of the class. + /// + public MandelbrotSetSeries() + { + this.TrackerFormatString = "X: {0:0.000}\r\nY: {1:0.000}\r\nIterations: {2}"; + } + + /// + /// Gets or sets the color axis. + /// + /// The color axis. + /// The Maximum value of the ColorAxis defines the maximum number of iterations. + public LinearColorAxis ColorAxis { get; protected set; } + + /// + /// Gets or sets the color axis key. + /// + /// The color axis key. + public string ColorAxisKey { get; set; } + + /// + /// Gets the point on the series that is nearest the specified point. + /// + /// The point. + /// Interpolate the series if this flag is set to true. + /// A TrackerHitResult for the current hit. + public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) + { + var p = this.InverseTransform(point); + var it = this.Solve(p.X, p.Y, (int)this.ColorAxis.ActualMaximum + 1); + return new TrackerHitResult + { + Series = this, + DataPoint = p, + Position = point, + Item = null, + Index = -1, + Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, null, p.X, p.Y, it) + }; + } + + /// + /// Renders the series on the specified render context. + /// + /// The rendering context. + public override void Render(IRenderContext rc) + { + var p0 = this.Transform(this.XAxis.ActualMinimum, this.YAxis.ActualMinimum); + var p1 = this.Transform(this.XAxis.ActualMaximum, this.YAxis.ActualMaximum); + var w = (int)(p1.X - p0.X); + var h = (int)(p0.Y - p1.Y); + int maxIterations = (int)this.ColorAxis.ActualMaximum + 1; + var pixels = new OxyColor[w, h]; + + ParallelFor( + 0, + h, + i => + { + double y = this.YAxis.ActualMaximum - ((double)i / (h - 1) * (this.YAxis.ActualMaximum - this.YAxis.ActualMinimum)); + for (int j = 0; j < w; j++) + { + double x = this.XAxis.ActualMinimum + + ((double)j / (w - 1) + * (this.XAxis.ActualMaximum - this.XAxis.ActualMinimum)); + var iterations = Solve(x, y, maxIterations); + pixels[j, i] = this.ColorAxis.GetColor((double)iterations); + } + }); + + var bitmap = OxyImage.Create(pixels, ImageFormat.Png); + rc.DrawImage(bitmap, p0.X, p1.Y, p1.X - p0.X, p0.Y - p1.Y, 1, true); + } + + /// + /// Calculates the escape time for the specified point. + /// + /// The x0. + /// The y0. + /// The max number of iterations. + /// The number of iterations. + protected virtual int Solve(double x0, double y0, int maxIterations) + { + int iteration = 0; + double x = 0; + double y = 0; + while ((x * x) + (y * y) <= 4 && iteration < maxIterations) + { + double xtemp = (x * x) - (y * y) + x0; + y = (2 * x * y) + y0; + x = xtemp; + iteration++; + } + + return iteration; + } + + /// + /// Ensures that the axes of the series is defined. + /// + protected override void EnsureAxes() + { + base.EnsureAxes(); + this.ColorAxis = this.ColorAxisKey != null ? + this.PlotModel.GetAxis(this.ColorAxisKey) as LinearColorAxis : + this.PlotModel.DefaultColorAxis as LinearColorAxis; + } + + /// + /// Executes a serial for loop. + /// + /// The start index (inclusive). + /// The end index (exclusive). + /// The action that is invoked once per iteration. + private static void SerialFor(int i0, int i1, Action action) + { + for (int i = i0; i < i1; i++) + { + action(i); + } + } + + /// + /// Executes a parallel for loop using ThreadPool. + /// + /// The start index (inclusive). + /// The end index (exclusive). + /// The action that is invoked once per iteration. + private static void ParallelFor(int i0, int i1, Action action) + { + // Environment.ProcessorCount is not available here. Use 4 processors. + int p = 4; + + // Initialize wait handles + var doneEvents = new WaitHandle[p]; + for (int i = 0; i < p; i++) + { + doneEvents[i] = new ManualResetEvent(false); + } + + // Invoke the action of a partition of the range + Action invokePartition = (k, j0, j1) => + { + for (int i = j0; i < j1; i++) + { + action(i); + } + + ((ManualResetEvent)doneEvents[k]).Set(); + }; + + // Start p background threads + int n = (i1 - i0 + p - 1) / p; + for (int i = 0; i < p; i++) + { + int k = i; + int j0 = i0 + (i * n); + var j1 = Math.Min(j0 + n, i1); + Task.Factory.StartNew( + () => invokePartition(k, j0, j1), + CancellationToken.None, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); + } + + // Wait for the threads to finish + foreach (var wh in doneEvents) + { + wh.WaitOne(); + } + } + } + + + private class JuliaSetSeries : MandelbrotSetSeries + { + public double C1 { get; set; } + public double C2 { get; set; } + + protected override int Solve(double x0, double y0, int maxIterations) + { + int iteration = 0; + double x = x0; + double y = y0; + double cr = this.C1; + double ci = this.C2; + while ((x * x) + (y * y) <= 4 && iteration < maxIterations) + { + double xtemp = (x * x) - (y * y) + cr; + y = (2 * x * y) + ci; + x = xtemp; + iteration++; + } + + return iteration; + } + } + + private class CustomAxis : LinearAxis + { + public IList MajorTicks { get; } = new List(); + public IList MinorTicks { get; } = new List(); + public IList Labels { get; } = new List(); + + public override void GetTickValues(out IList majorLabelValues, out IList majorTickValues, out IList minorTickValues) + { + majorTickValues = majorLabelValues = this.MajorTicks.Where(d => d >= this.ActualMinimum && d <= this.ActualMaximum).ToList(); + minorTickValues = this.MinorTicks.Where(d => d >= this.ActualMinimum && d <= this.ActualMaximum).ToList(); + } + + protected override string FormatValueOverride(double x) + { + return this.Labels[this.MajorTicks.IndexOf(x)]; + } + } + + } +} diff --git a/Source/Examples/ExampleLibrary/Misc/XkcdExamples.cs b/Source/Examples/ExampleLibrary/Misc/XkcdExamples.cs new file mode 100644 index 0000000..aed9af5 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Misc/XkcdExamples.cs @@ -0,0 +1,145 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Plot examples in XKCD style. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + /// + /// Plot examples in XKCD style. + /// + [Examples("XKCD")] + public static class XkcdExamples + { + /// + /// Xkcd style example #1. + /// + /// A . + [Example("Test #1")] + public static PlotModel Test1() + { + var model = new PlotModel + { + Title = "XKCD style plot", + Subtitle = "Install the 'Humor Sans' font for the best experience", + RenderingDecorator = rc => new XkcdRenderingDecorator(rc) + }; + model.Series.Add(new FunctionSeries(Math.Sin, 0, 10, 50, "sin(x)")); + return model; + } + + + /// + /// Xkcd style example #2. + /// + /// A . + [Example("Test #2")] + public static PlotModel Test2() + { + var model = new PlotModel + { + Title = "Test #2", + RenderingDecorator = rc => new XkcdRenderingDecorator(rc) + }; + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 8, Title = "INTENSITY" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "TIME" }); + + var s1 = new LineSeries + { + Color = OxyColors.Cyan, + StrokeThickness = 4, + }; + + var s2 = new LineSeries + { + Color = OxyColors.White, + StrokeThickness = 14, + }; + + var s3 = new LineSeries + { + Color = OxyColors.Red, + StrokeThickness = 4, + }; + + int n = 257; + double x0 = 1; + double x1 = 9; + for (int i = 0; i < n; i++) + { + var x = x0 + ((x1 - x0) * i / (n - 1)); + var y1 = 1.5 + (10.0 * (Math.Sin(x) * Math.Sin(x) / Math.Sqrt(x)) * Math.Exp(-0.5 * (x - 5.0) * (x - 5.0))); + var y2 = 3.0 + (10.0 * (Math.Sin(x) * Math.Sin(x) / Math.Sqrt(x)) * Math.Exp(-0.5 * (x - 7.0) * (x - 7.0))); + s1.Points.Add(new DataPoint(x, y1)); + s2.Points.Add(new DataPoint(x, y2)); + s3.Points.Add(new DataPoint(x, y2)); + } + + model.Series.Add(s1); + model.Series.Add(s2); + model.Series.Add(s3); + + return model; + } + + + /// + /// Xkcd style example #3. + /// + /// A . + [Example("Test #3")] + public static PlotModel Test3() + { + var model = new PlotModel + { + Title = "Test #3", + RenderingDecorator = rc => new XkcdRenderingDecorator(rc) + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + var s1 = new BarSeries { Title = "Series 1", IsStacked = false, StrokeColor = OxyColors.Black, StrokeThickness = 1, XAxisKey = "x", YAxisKey = "y" }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 137 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + + var s2 = new BarSeries { Title = "Series 2", IsStacked = false, StrokeColor = OxyColors.Black, StrokeThickness = 1, XAxisKey = "x", YAxisKey = "y" }; + s2.Items.Add(new BarItem { Value = 12 }); + s2.Items.Add(new BarItem { Value = 14 }); + s2.Items.Add(new BarItem { Value = 120 }); + s2.Items.Add(new BarItem { Value = 26 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Bottom, Key = "y" }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + var valueAxis = new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0, Key = "x" }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Resources/Bergensbanen.csv b/Source/Examples/ExampleLibrary/Resources/Bergensbanen.csv new file mode 100644 index 0000000..da13931 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Resources/Bergensbanen.csv @@ -0,0 +1,26 @@ +Stasjon;km;moh;609;61;601;1405;607;603;63;605;62;602;608;604;64;610;1404;606 +Oslo;0.00;4.0;0631;0811;1037;;1227;1437;1609;2311;1432;1736;1956;2210;2236;2348;;0626 +Lysaker;7.00;7.5;0642;0822;1048;;1238;1448;1620;2322;1420;1724;1944;2158;2224;;; +Asker;23.83;104.6;0653;0832;1059;;1249;1458;1630;2334;1409;1713;1932;2144;2214;2324;;0555 +Drammen;52.86;2.2;0708;0846;1115;;1303;1513;1645;2351;1354;1701;1914;2125;2201;2307;;0540 +Hokksund;70.22;8.0;;;1136;;1320;1531;;0007;;1638;1854;2111;2140;;;0525 +Vikersund;95.91;67.1;;;1158;;1349;1552;;0029;;1617;1833;2048;;;;0503 +Hønefoss;124.21;96.8;0804;0937;1222;;1414;1619;1736;0056;1304;1555;1811;2025;2100;2201;;0442 +Flå;186.64;155.0;;;1314;;;1712;;;;1503;1715;1934;;2108;;0349 +Nesbyen;220.06;168.8;;1045;1340;;1532;1744;1845;0223;1152;1436;1643;1909;1949;2041;;0321 +Gol;237.02;207.4;0930;1100;1354;;1545;1800;1900;0239;1141;1423;1630;1858;1938;2028;;0308 +Ål;262.85;436.6;0950;1123;1419;1520;1608;1832;1921;0305;1121;1400;1609;1833;1919;2007;1957;0246 +Geilo;287.38;794.2;1013;1145;1442;1545;1630;1855;1942;0328;1059;1339;1547;1812;1857;1946;1939;0224 +Ustaoset;299.31;990.6;;1156;1454;1556;1643;1905;1953;0341;1048;1326;1536;1800;1845;;1927;0209 +Haugastøl;310.14;988.0;1042;;1505;1606;1655;1916;;0352;;1315;1527;1750;;1922;;0158 +Finse;336.74;1222.2;1108;1224;1526;1626;1717;1937;2021;0417;1019;1254;1508;1730;1818;1900;1854;0138 +Hallingskeid;357.44;1110.1;1123;;1538;1637;1732;1950;;;;1239;1454;1711;;1842;1839; +Myrdal;370.44;866.8;1137;1253;1551;1650;1746;2003;2045;0445;0953;1225;1440;1657;1752;1828;1825;0105 +;370.44;866.8;1220;1258;1556;1652;1751;2004;2047;0445;0950;1220;1439;1652;1750;1823;1822;0101 +// Upsete;376.79;850.2;;;;;;;;;;;;;;;; +// Mjølfjell;388.86;627.2;;;;;;;;;;;;;;;; +Voss;419.96;56.5;1312;1343;1640;1738;1836;2048;2130;0537;0910;1139;1355;1608;1710;1736;1740;0015 +Dale;459;43.4;;;;;1903;;2156;0608;0836;1109;;;;;;2344 +Vaksdal;475.17;16.0;;;;;;;;0626;;;;;;;;2326 +Arna;501.43;8.0;1410;1441;1740;1840;1935;2155;2228;0644;0806;1037;1248;1506;1606;1618;1637;2307 +Bergen;526.64;3.9;1422;1442;1752;1850;1945;2204;2235;0656;0758;1028;1240;1458;1558;1610;1628;2258 diff --git a/Source/Examples/ExampleLibrary/Resources/DodgyContourData.tsv b/Source/Examples/ExampleLibrary/Resources/DodgyContourData.tsv new file mode 100644 index 0000000..6e4e0c8 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Resources/DodgyContourData.tsv @@ -0,0 +1,64 @@ +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.871911335 7.831477624 0.983750619 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50.52296489 123.0626703 150.4809042 148.0423619 124.0301307 82.2105702 26.1248496 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 14.48472472 76.65796513 104.1487589 59.62522164 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40.96918334 228.867633 321.8916552 348.7749208 332.1704768 284.6607991 212.2590838 120.5447125 18.56579865 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 75.36704272 164.7479561 243.5157425 276.2281043 212.6451587 0 0 0 0 0 0 0 0 0 0 0 0 0 0 169.6229356 414.2998674 529.4903613 554.600307 520.8963728 446.0365189 338.7348661 206.9839606 63.26466815 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 9.205781116 82.01916001 177.9000059 286.1254047 381.0470127 417.5995668 331.7330427 50.67054507 0 0 0 0 0 0 0 0 0 0 0 0 0 254.5911564 559.8684317 698.5666103 721.7210912 670.0277041 566.7604911 423.6634095 251.3920058 66.11160911 0 0 0 0 0 0 0 0 0 0 12.31094715 22.21346912 25.59197493 26.43800533 26.58281418 26.59833221 26.59926678 26.59929445 26.59929479 26.59929479 26.59929479 26.59929479 26.59929479 +53.37068509 41.26107552 27.41086039 11.99426509 0 0 0 0 0 0 0 41.7970819 124.8883295 235.7218382 361.3434747 470.5933532 508.5883198 397.2152406 47.64435861 0 0 0 0 0 0 0 0 0 0 0 0 0 263.4343469 630.3404002 793.01658 814.5403423 745.4180361 614.8323686 437.7584478 227.6428153 4.399301626 0 0 0 0 0 0 0 0 0 0 25.7435405 38.71806274 43.14451668 44.25296529 44.4426903 44.46302163 44.46424608 44.46428234 44.46428279 44.46428279 44.46428279 44.46428279 44.46428279 +82.38994802 67.31000004 49.99089534 30.5974238 9.650305616 0 0 0 0 0 0 40.67887841 132.6142856 256.4992529 397.1226646 517.8675476 554.2038267 414.2566619 0 0 0 0 0 0 0 0 0 0 0 0 0 0 184.7442373 611.3015583 797.0837711 817.1238141 731.7231522 576.040388 368.3698962 124.9724275 0 0 0 0 0 0 0 0 0 0 0 22.73737943 39.22952506 44.85587328 46.26478712 46.50594049 46.53178299 46.53333935 46.53338544 46.53338601 46.53338601 46.53338601 46.53338601 46.53338601 +100.0514966 82.19459945 61.62955548 38.51010449 13.38936805 0 0 0 0 0 0 28.69892496 128.099478 263.0089224 415.9663596 545.0829029 576.6182786 405.6427925 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26.45166586 508.0105319 714.6366562 732.8247181 632.3305988 454.1682153 219.9419931 0 0 0 0 0 0 0 0 0 0 0 0 4.266615693 24.59998934 31.53655728 33.27356116 33.57087119 33.60273157 33.60465035 33.60470717 33.60470787 33.60470788 33.60470788 33.60470788 33.60470788 +122.8334547 102.5701693 79.19582959 52.85700093 24.13839094 0 0 0 0 0 0 26.67039734 132.676593 277.0608032 440.1416853 575.0243497 599.3572442 396.1084013 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 336.4533631 560.816221 576.5257982 462.2071332 264.4570142 8.090838542 0 0 0 0 0 0 0 0 0 0 0 0 0 1.658299426 9.967160553 12.04779672 12.40392365 12.44208696 12.44438534 12.4444534 12.44445424 12.44445424 12.44445424 12.44445424 12.44445424 +150.8756496 128.7169729 103.1413067 74.29770269 42.80800051 10.03324302 0 0 0 0 0 38.96757886 151.4983328 304.665598 476.6171093 615.762465 631.8154359 396.7036583 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112.1771456 351.3212641 364.4083058 238.1766917 24.40858789 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +164.883999 141.4038837 114.3132309 83.7770015 50.46438143 15.83192167 0 0 0 0 0 48.87158927 168.520825 330.6053457 511.1783695 654.2917109 662.4254322 397.544702 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94.84242787 106.4592201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +135.8082612 111.525432 83.54080187 52.04792823 17.77347026 0 0 0 0 0 0 26.60104155 154.1294117 325.5891147 515.0555194 662.5886242 664.1398477 372.760189 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +42.00532338 17.24396944 0 0 0 0 0 0 0 0 0 0 81.02542685 261.8079793 460.0937634 612.3583587 608.73835 294.3813556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 127.4598081 333.2553423 489.4847368 481.2055231 146.6456816 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 142.293441 300.0913869 286.1544333 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2.091369399 2.783675148 2.857864092 2.862332102 2.862464416 2.862466047 2.862466054 2.862466054 2.862466054 2.862466054 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66.45652912 44.35644355 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1.350971927 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +81.4987815 13.21809704 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +149.6905637 79.98893327 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/Source/Examples/ExampleLibrary/Resources/OxyPlot.png b/Source/Examples/ExampleLibrary/Resources/OxyPlot.png new file mode 100644 index 0000000..ffb8774 Binary files /dev/null and b/Source/Examples/ExampleLibrary/Resources/OxyPlot.png differ diff --git a/Source/Examples/ExampleLibrary/Resources/WorldPopulation.xml b/Source/Examples/ExampleLibrary/Resources/WorldPopulation.xml new file mode 100644 index 0000000..ed5cef2 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Resources/WorldPopulation.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/ExampleLibrary/Resources/X.txt b/Source/Examples/ExampleLibrary/Resources/X.txt new file mode 100644 index 0000000..16a4751 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Resources/X.txt @@ -0,0 +1,64 @@ +0.01 +0.0124519708473503 +0.0155051577983263 +0.0193069772888325 +0.0240409918350997 +0.0299357729472049 +0.0372759372031494 +0.0464158883361278 +0.0577969288415331 +0.0719685673001151 +0.0896150501946605 +0.111588399250775 +0.138949549437314 +0.173019573884589 +0.215443469003188 +0.268269579527972 +0.334048498351324 +0.415956216307185 +0.517947467923121 +0.644946677103762 +0.803085722139151 +1 +1.24519708473503 +1.55051577983262 +1.93069772888325 +2.40409918350997 +2.99357729472049 +3.72759372031494 +4.64158883361278 +5.77969288415331 +7.19685673001151 +8.96150501946604 +11.1588399250775 +13.8949549437314 +17.3019573884589 +21.5443469003188 +26.8269579527972 +33.4048498351324 +41.5956216307184 +51.7947467923121 +64.4946677103762 +80.3085722139151 +100 +124.519708473503 +155.051577983262 +193.069772888325 +240.409918350997 +299.357729472049 +372.759372031494 +464.158883361277 +577.969288415331 +719.685673001151 +896.150501946605 +1115.88399250775 +1389.49549437314 +1730.19573884589 +2154.43469003188 +2682.69579527972 +3340.48498351324 +4159.56216307184 +5179.4746792312 +6449.46677103762 +8030.8572213915 +10000 diff --git a/Source/Examples/ExampleLibrary/Resources/Y.txt b/Source/Examples/ExampleLibrary/Resources/Y.txt new file mode 100644 index 0000000..641b915 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Resources/Y.txt @@ -0,0 +1,64 @@ +1E-12 +1.24519708473503E-12 +1.55051577983262E-12 +1.93069772888325E-12 +2.40409918350997E-12 +2.99357729472049E-12 +3.72759372031494E-12 +4.64158883361277E-12 +5.77969288415333E-12 +7.19685673001153E-12 +8.96150501946605E-12 +1.11588399250775E-11 +1.38949549437314E-11 +1.73019573884589E-11 +2.15443469003189E-11 +2.68269579527973E-11 +3.34048498351324E-11 +4.15956216307184E-11 +5.1794746792312E-11 +6.44946677103763E-11 +8.03085722139152E-11 +1E-10 +1.24519708473503E-10 +1.55051577983262E-10 +1.93069772888325E-10 +2.40409918350997E-10 +2.99357729472049E-10 +3.72759372031494E-10 +4.64158883361277E-10 +5.77969288415333E-10 +7.19685673001153E-10 +8.96150501946605E-10 +1.11588399250775E-09 +1.38949549437314E-09 +1.73019573884589E-09 +2.15443469003188E-09 +2.68269579527973E-09 +3.34048498351324E-09 +4.15956216307184E-09 +5.1794746792312E-09 +6.44946677103763E-09 +8.03085722139152E-09 +1E-08 +1.24519708473503E-08 +1.55051577983262E-08 +1.93069772888325E-08 +2.40409918350997E-08 +2.99357729472049E-08 +3.72759372031494E-08 +4.64158883361277E-08 +5.77969288415331E-08 +7.19685673001151E-08 +8.96150501946605E-08 +1.11588399250775E-07 +1.38949549437314E-07 +1.73019573884589E-07 +2.15443469003188E-07 +2.68269579527972E-07 +3.34048498351324E-07 +4.15956216307184E-07 +5.1794746792312E-07 +6.44946677103762E-07 +8.0308572213915E-07 +1E-06 diff --git a/Source/Examples/ExampleLibrary/Resources/west0479.mtx b/Source/Examples/ExampleLibrary/Resources/west0479.mtx new file mode 100644 index 0000000..4dc4550 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Resources/west0479.mtx @@ -0,0 +1,1924 @@ +%%MatrixMarket matrix coordinate real general +%------------------------------------------------------------------------------- +% UF Sparse Matrix Collection, Tim Davis +% http://www.cise.ufl.edu/research/sparse/matrices/HB/west0479 +% name: HB/west0479 +% [U 8 STAGE COLUMN SECTION, ALL SECTIONS RIGOROUS ( CHEM. ENG. )] +% id: 267 +% date: 1983 +% author: A. Westerberg +% ed: I. Duff, R. Grimes, J. Lewis +% fields: title A Zeros name id date author ed kind +% kind: chemical process simulation problem +%------------------------------------------------------------------------------- +479 479 1910 +25 1 1 +31 1 -.03764813 +87 1 -.3442396 +26 2 1 +31 2 -.02452262 +88 2 -.3737086 +27 3 1 +31 3 -.03661304 +89 3 -.8369379 +28 4 130 +29 4 -2.433767 +29 5 1 +30 5 -1.614091 +30 6 1.614091 +31 6 -.2187321 +87 6 -1 +88 6 -1 +89 6 -1 +32 7 -1.138352 +43 7 .03669428 +111 7 .09931636 +112 7 .09931636 +113 7 .09931636 +33 8 -.5 +43 8 .01611729 +111 8 .08724576 +34 9 -.3611918 +43 9 .01164286 +112 9 .1050415 +35 10 -.3218876 +43 10 .01037591 +113 10 .1404166 +36 11 -.4362416 +37 11 -.7680425 +38 11 -.1430279 +39 11 -.1593886 +37 12 1 +43 12 -.04856082 +111 12 -.2628684 +38 13 1 +43 13 -.03092595 +112 13 -.2790128 +39 14 1 +43 14 -.04612359 +113 14 -.6241882 +40 15 5.282436 +42 15 -.6123921 +41 16 .2886822 +42 16 -.2163815 +42 17 1.328774 +43 17 -.3694686 +111 17 -1 +112 17 -1 +113 17 -1 +2 18 48.17647 +8 18 -1 +11 18 -3.347484e-5 +3 19 83.5 +9 19 -1 +12 19 -4.136539e-5 +4 20 171.9412 +10 20 -1 +13 20 -8.484345e-5 +5 21 96.65138 +8 21 2.5 +11 21 3.347484e-5 +6 22 168.2706 +9 22 2.5 +12 22 4.136539e-5 +7 23 347.5872 +10 23 2.5 +13 23 8.484345e-5 +8 24 1 +17 24 -.1106967 +27 24 1.605232 +9 25 1 +17 25 -.08980852 +10 26 1 +17 26 -.1517369 +11 27 1.010455 +18 27 -.5 +12 28 1.005978 +18 28 -.3 +13 29 1.002885 +18 29 -.2 +14 30 1 +17 30 -.1811855 +15 31 1 +17 31 -.2400239 +16 32 1 +17 32 -.2265484 +17 33 1 +19 33 -1 +30 33 1.5 +42 33 .5 +18 34 1 +20 34 -316220 +23 34 -12323.69 +24 34 -1 +30 34 -35226.8 +41 34 18449.02 +19 35 5.298339 +21 35 .002452687 +20 36 1080.859 +21 36 -.2050215 +21 37 .144192 +22 37 63.05986 +30 37 -.1159299 +22 38 -18449.02 +24 38 .8453339 +40 38 -18449.02 +41 38 -15595.58 +23 39 1 +30 39 .2020493 +42 39 -.885471 +24 40 .0001000234 +30 40 2.448339 +42 40 .816113 +68 41 1 +74 41 -.0002278669 +99 41 -.2624395 +69 42 1 +74 42 -.0004188763 +100 42 -.3216196 +70 43 1 +74 43 -.001576933 +101 43 -.7264761 +71 44 300 +72 44 -2.851891 +72 45 1 +73 45 -.2870159 +73 46 .2870159 +74 46 -.004341322 +99 46 -1 +100 46 -1 +101 46 -1 +75 47 -1.138352 +86 47 .04200286 +123 47 .9414806 +124 47 .9414806 +125 47 .9414806 +76 48 -.3218876 +86 48 .011877 +123 48 1.331095 +77 49 -.3611918 +86 49 .01332724 +124 49 .9957529 +78 50 -.5 +86 50 .01844898 +125 50 .827056 +79 51 -1 +80 51 -19.24 +81 51 -3.803 +82 51 -9.481 +80 52 1 +86 52 -.0008875784 +123 52 -.09947392 +81 53 1 +86 53 -.001331368 +124 53 -.09947392 +82 54 1 +86 54 -.002218946 +125 54 -.09947392 +83 55 1.177613 +85 55 -3.108963 +84 56 .9919425 +85 56 -2.640056 +85 57 3.192112 +86 57 -.04461363 +123 57 -1 +124 57 -1 +125 57 -1 +45 58 109.8688 +51 58 -1 +54 58 -3.30811e-5 +46 59 191.3846 +52 59 -1 +55 59 -4.108467e-5 +47 60 395.4796 +53 60 -1 +56 60 -8.456383e-5 +48 61 221.7339 +51 61 2.5 +54 61 3.30811e-5 +49 62 387.0092 +52 62 2.5 +55 62 4.108467e-5 +50 63 800.8165 +53 63 2.5 +56 63 8.456383e-5 +51 64 1 +60 64 -.009170229 +52 65 1 +60 65 -.0464411 +53 66 1 +60 66 -.4899919 +54 67 1.00453 +61 67 -.2 +55 68 1.002591 +61 68 -.3 +56 69 1.00125 +61 69 -.5 +57 70 1 +60 70 -.03750053 +58 71 1 +60 71 -.124143 +59 72 1 +60 72 -.2927532 +60 73 1 +62 73 -1 +73 73 .1853733 +85 73 .06179109 +61 74 1 +63 74 -316220 +66 74 -16364.19 +67 74 -1 +73 74 -4696.782 +84 74 131.854 +62 75 22.12913 +64 75 .9537526 +63 76 2494.29 +64 76 -1.021587 +64 77 .8878281 +65 77 1.040042 +73 77 -2.640056 +65 78 -131.854 +67 78 .00805747 +83 78 -131.854 +84 78 -1.062409 +66 79 1 +73 79 .1016426 +85 79 -.06179109 +67 80 .007645257 +73 80 23.09895 +85 80 7.699649 +31 81 1 +244 81 1 +43 82 1 +1 83 1 +17 83 -3.850231 +18 83 -8.459935e-5 +31 83 2.01591 +35 83 1 +43 83 1.596171 +243 83 -.7897512 +74 84 1 +388 84 .8817562 +86 85 1 +44 86 1 +60 86 -2.79376 +61 86 -8.445823e-5 +74 86 2.015665 +78 86 1 +86 86 1.593994 +384 86 0 +387 86 -.961915 +385 87 .002424669 +386 87 .03036278 +387 87 .6730451 +388 87 1.45936 +96 88 .01689661 +97 88 .03484803 +98 88 -.06008018 +120 88 -.5552717 +121 88 -.4770398 +122 88 -.1858293 +141 88 -1 +142 88 -1 +143 88 -1 +185 88 -55.18857 +186 88 -95.67686 +187 88 -215.8377 +389 88 1 +438 88 1 +439 88 1 +440 88 1 +441 88 1 +442 88 1 +443 88 1 +450 88 -.001890756 +451 88 -.00153114 +452 88 -.001013726 +455 88 2.5 +456 88 26.0637 +458 88 1 +459 88 -1.5 +461 88 -9.603181 +462 88 -9.454185 +463 88 -9.437681 +464 88 -48.29572 +472 88 .9075922 +473 88 -4.375967 +474 88 -8.997992 +475 88 -8.881958 +476 88 1 +182 89 1 +183 89 1 +184 89 1 +391 89 1 +455 89 -1 +456 89 -26.0637 +458 89 -1 +468 89 1 +388 90 -1.45936 +467 90 1 +479 91 1 +203 92 -1 +204 92 -1 +205 92 -1 +209 92 1 +210 92 1 +211 92 1 +382 92 56.9531 +385 92 .7058325 +437 92 1 +453 92 -.6491372 +454 92 -3.294841e-5 +467 92 .5380748 +469 92 1 +479 92 .08247112 +203 93 -1 +204 93 -1 +205 93 -1 +209 93 1 +210 93 1 +211 93 1 +383 93 11.58384 +386 93 .7058325 +437 93 1 +453 93 -1.021542 +454 93 -4.099033e-5 +467 93 -.3630248 +470 93 1 +479 93 .06952261 +203 94 -1 +204 94 -1 +205 94 -1 +209 94 1 +210 94 1 +211 94 1 +384 94 .3209631 +387 94 .7058325 +437 94 1 +453 94 -2.049007 +454 94 -8.447003e-5 +467 94 .9135362 +471 94 1 +479 94 .8397638 +241 95 .5508352 +242 95 .4489223 +243 95 .0002425203 +244 95 .4052833 +108 96 -.06727662 +109 96 -.1570061 +110 96 -.0974757 +132 96 -.2506007 +133 96 -.2802617 +134 96 .1008491 +245 96 -1 +395 96 1 +396 96 1 +397 96 1 +398 96 1 +399 96 1 +400 96 1 +407 96 -.002863602 +408 96 -.002316259 +409 96 -.00153089 +412 96 2.5 +413 96 11.5878 +415 96 1 +416 96 -1.101224 +418 96 -1.364432 +419 96 -1.218821 +420 96 -1.210859 +421 96 -34.62105 +429 96 .6031359 +430 96 -.5996384 +431 96 -1.403392 +432 96 -1.370386 +433 96 1 +246 97 1 +412 97 -1 +413 97 -11.5878 +415 97 -1 +425 97 1 +244 98 -.4052833 +424 98 1 +436 99 1 +160 100 -.859384 +161 100 -.773339 +162 100 -.795174 +238 100 -1 +241 100 1 +394 100 1 +410 100 -1.623659 +411 100 -3.303278e-5 +424 100 3.572035 +426 100 1 +436 100 .9243532 +160 101 -1.171821 +161 101 -1.277352 +162 101 -1.250508 +239 101 -1 +242 101 1 +394 101 1 +410 101 -2.460289 +411 101 -4.105081e-5 +424 101 -2.178533 +427 101 1 +436 101 .6509842 +160 102 -2.328047 +161 102 -2.416155 +162 102 -2.512166 +240 102 -1 +243 102 1 +394 102 1 +410 102 -4.75362 +411 102 -8.45305e-5 +424 102 6.16714 +428 102 1 +436 102 3.396691 +241 103 .04373657 +242 103 .5739646 +243 103 .158349 +244 103 .1878125 +253 103 -.04434413 +254 103 -.5819378 +255 103 -.1605487 +256 103 -1 +135 104 -1 +136 104 -1 +137 104 -1 +151 104 -62.6809 +152 104 -123.89 +153 104 -464.3555 +245 104 1 +248 104 -.05164655 +249 104 -.3241762 +148 105 1 +149 105 1 +150 105 1 +247 105 1 +244 106 -.1878125 +248 106 1 +256 106 1 +249 107 1 +147 108 1 +169 108 -1 +170 108 -1 +171 108 -1 +175 108 1 +176 108 1 +177 108 1 +238 108 9.773875 +241 108 .7760502 +248 108 7.252831 +249 108 .78041 +253 108 -.7868306 +147 109 1 +169 109 -1 +170 109 -1 +171 109 -1 +175 109 1 +176 109 1 +177 109 1 +239 109 .6069821 +242 109 .7760502 +248 109 -2.389508 +249 109 .6849398 +254 109 -.7868306 +147 110 1 +169 110 -1 +170 110 -1 +171 110 -1 +175 110 1 +176 110 1 +177 110 1 +240 110 .001188564 +243 110 .7760502 +248 110 11.55883 +249 110 2.202644 +255 110 -.7868306 +363 111 -.1705148 +364 111 -.4342963 +365 111 -.2667421 +366 111 -2.609302 +385 111 .1956447 +386 111 .4983016 +387 111 .3060537 +388 111 .422396 +215 112 1 +216 112 1 +217 112 1 +218 112 1 +219 112 1 +220 112 1 +227 112 -.001890756 +228 112 -.00153114 +229 112 -.001013726 +232 112 2.5 +233 112 16.67241 +235 112 1 +236 112 -1.5 +389 112 -1 +392 112 -.4621213 +393 112 -.1234962 +232 113 -1 +233 113 -16.67241 +235 113 -1 +368 113 -1 +369 113 -1 +390 113 1 +366 114 2.609302 +388 114 -.422396 +392 114 1 +393 115 1 +181 116 1 +194 116 -.5869762 +195 116 -.5065155 +196 116 -.5139918 +230 116 -1.036685 +231 116 -3.294841e-5 +360 116 0 +363 116 -.8715531 +382 116 -1 +385 116 1 +392 116 2.63998 +393 116 .5574207 +181 117 1 +194 117 -.8001637 +195 117 -.836409 +196 117 -.8081026 +230 117 -1.637695 +231 117 -4.099033e-5 +361 117 0 +364 117 -.8715531 +383 117 -1 +386 117 1 +392 117 -1.773678 +393 117 .4075422 +181 118 1 +194 118 -1.589389 +195 118 -1.581811 +196 118 -1.623118 +230 118 -3.205686 +231 118 -8.447003e-5 +362 118 0 +365 118 -.8715531 +384 118 -1 +387 118 1 +392 118 4.467609 +393 118 2.247529 +93 119 -1 +96 119 -1 +248 119 -.4042156 +262 119 -.1818777 +284 119 -.1563455 +306 119 -.1545699 +328 119 -.1521778 +350 119 -.0919058 +372 119 -.007870537 +94 120 -1 +97 120 -1 +248 120 -1.809171 +262 120 -3.189655 +284 120 -3.349019 +306 120 -3.358644 +328 120 -3.308585 +350 120 -1.96787 +372 120 -.1133356 +95 121 -1 +98 121 -1 +248 121 -2.456602 +262 121 -4.101128 +284 121 -4.290892 +306 121 -4.302603 +328 121 -4.254147 +350 121 -2.952389 +372 121 -1.157365 +93 122 -.008121496 +96 122 -.01689661 +248 122 -.00453876 +262 122 -.00217052 +284 122 -.001874069 +306 122 -.001853318 +328 122 -.001824837 +350 122 -.001106561 +372 122 -.0001054494 +94 123 -.01674999 +97 123 -.03484803 +248 123 -.04189692 +262 123 -.07850668 +284 123 -.08279351 +306 123 -.08305532 +328 123 -.08182638 +350 123 -.04886605 +372 123 -.003131732 +95 124 -.02887803 +98 124 -.06008018 +248 124 -.09808224 +262 124 -.1740281 +284 124 -.1828855 +306 124 -.1834374 +328 124 -.1813914 +350 124 -.1263972 +372 124 -.05513677 +105 125 -1 +108 125 -1 +264 125 -.7636232 +286 125 -.5413211 +308 125 -.5290753 +330 125 -.528326 +352 125 -.5296534 +374 125 -.5990106 +392 125 -.5746768 +106 126 -1 +109 126 -1 +264 126 -1.467979 +286 126 -1.289806 +308 126 -1.279992 +330 126 -1.279385 +352 126 -1.280174 +374 126 -1.360143 +392 126 -.714919 +107 127 -1 +110 127 -1 +264 127 -.004370857 +286 127 -.003954101 +308 127 -.003931803 +330 127 -.003947668 +352 127 -.004749023 +374 127 -.07245539 +392 127 -1.602364 +105 128 -.1122933 +108 128 -.06727662 +264 128 -.05460137 +286 128 -.03887722 +308 128 -.03800866 +330 128 -.03795899 +352 128 -.03820886 +374 128 -.04808549 +392 128 -.05817862 +106 129 -.2620633 +109 129 -.1570061 +264 129 -.2449608 +286 129 -.2161806 +308 129 -.2145974 +330 129 -.2145191 +352 129 -.215523 +374 129 -.25481 +392 129 -.1689075 +107 130 -.1626995 +110 130 -.0974757 +264 130 -.0004528176 +286 130 -.0004114529 +308 130 -.0004092503 +330 130 -.0004109467 +352 130 -.0004963737 +374 130 -.008427185 +392 130 -.2350352 +117 131 -1 +120 131 -1 +249 131 -.06970284 +263 131 -.01924332 +285 131 -.01583793 +307 131 -.01561791 +329 131 -.01558321 +351 131 -.01471856 +373 131 -.005759952 +118 132 -1 +121 132 -1 +249 132 -.7417136 +263 132 -.8023494 +285 132 -.8065847 +307 132 -.8068286 +329 132 -.8055031 +351 132 -.7492698 +373 132 -.197197 +119 133 -1 +122 133 -1 +249 133 -.5127598 +263 133 -.5252253 +285 133 -.5261413 +307 133 -.5262245 +329 133 -.5273027 +351 133 -.5723186 +373 133 -1.025242 +117 134 -.4657593 +120 134 -.9690031 +249 134 -.04488488 +263 134 -.01317012 +285 134 -.01088739 +307 134 -.01073924 +329 134 -.01071655 +351 134 -.01016303 +373 134 -.004425719 +118 135 -.5744023 +121 135 -1.195033 +249 135 -.5890342 +263 135 -.6772174 +285 135 -.6838018 +307 135 -.6842053 +329 135 -.6831561 +351 135 -.638044 +373 135 -.1868616 +119 136 -.2292285 +122 136 -.4769055 +249 136 -.1625065 +263 136 -.1769142 +285 136 -.1780062 +307 136 -.1780856 +329 136 -.17847 +351 136 -.1944925 +373 136 -.3877026 +129 137 -1 +132 137 -1 +265 137 -.3427279 +287 137 -.2911376 +309 137 -.2876937 +331 137 -.2874889 +353 137 -.2882318 +375 137 -.3026987 +393 137 -.1750789 +130 138 -1 +133 138 -1 +265 138 -1.062334 +287 138 -1.118506 +309 138 -1.122253 +331 138 -1.122512 +353 138 -1.123285 +375 138 -1.108234 +393 138 -.3511864 +131 139 -1 +134 139 -1 +265 139 -.002399982 +287 139 -.00260173 +309 139 -.002615627 +331 139 -.002628033 +353 139 -.003161735 +375 139 -.04479381 +393 139 -.5972309 +129 140 -2.018253 +132 140 -1.209166 +265 140 -.4404489 +287 140 -.3758029 +309 140 -.3714643 +331 140 -.3712405 +353 140 -.3737109 +375 140 -.4367288 +393 140 -.3185628 +130 141 -2.562688 +133 141 -1.535345 +265 141 -1.733513 +287 141 -1.833245 +309 141 -1.839915 +331 141 -1.840541 +353 141 -1.849286 +375 141 -2.030266 +393 141 -.8113705 +131 142 -.9255429 +134 142 -.5545067 +265 142 -.001414409 +287 142 -.001540086 +309 142 -.001548758 +331 142 -.001556274 +353 142 -.001879925 +375 142 -.0296374 +393 142 -.4983387 +135 143 -1.433892 +141 143 -2.157704 +266 143 -1.523971 +288 143 -1.530708 +310 143 -1.531148 +332 143 -1.531316 +354 143 -1.537533 +376 143 -1.710928 +136 144 -.943206 +142 144 -1.419326 +267 144 -1.00246 +289 144 -1.006891 +311 144 -1.007181 +333 144 -1.007291 +355 144 -1.011381 +377 144 -1.125439 +137 145 -.5964527 +143 145 -.8975353 +268 145 -.6339227 +290 145 -.6367252 +312 145 -.6369083 +334 145 -.6369781 +356 145 -.6395642 +378 145 -.7116909 +135 146 -1 +141 146 -1 +266 146 -1 +288 146 -1 +310 146 -1 +332 146 -1 +354 146 -1 +376 146 -1 +136 147 -1 +142 147 -1 +267 147 -1 +289 147 -1 +311 147 -1 +333 147 -1 +355 147 -1 +377 147 -1 +137 148 -1 +143 148 -1 +268 148 -1 +290 148 -1 +312 148 -1 +334 148 -1 +356 148 -1 +378 148 -1 +138 149 -1 +148 149 1 +238 149 .5508352 +139 150 -1 +149 150 1.647495 +239 150 .7395973 +140 151 -1 +150 151 841.3516 +240 151 .2040448 +144 152 -1 +182 152 1 +382 152 .1956447 +145 153 -1 +183 153 1 +383 153 .4983016 +146 154 -1 +184 154 3.115622 +384 154 .9535478 +395 155 66.22492 +401 155 -1 +404 155 -3.328257e-5 +396 156 115.0623 +402 156 -1 +405 156 -4.122831e-5 +397 157 237.3387 +403 157 -1 +406 157 -8.47069e-5 +398 158 133.245 +401 158 2.5 +404 158 3.328257e-5 +399 159 232.2639 +402 159 2.5 +405 159 4.122831e-5 +400 160 480.1821 +403 160 2.5 +406 160 8.47069e-5 +160 161 -.473379 +401 161 1 +410 161 -.2116876 +161 162 -.5734317 +402 162 1 +410 162 -.3166715 +162 163 -.0006092511 +403 163 1 +410 163 -3.511874e-7 +163 164 -4575.004 +404 164 1.007562 +411 164 -.5508352 +164 165 -3681.416 +405 165 1.004324 +411 165 -.4489223 +165 166 -1787.818 +406 166 1.002087 +411 166 -.0002425203 +160 167 -.5260564 +161 167 -.4259823 +407 167 1 +410 167 -.4704884 +160 168 -.0005645987 +162 168 -.4380098 +408 168 1 +410 168 -.0005049593 +161 169 -.0005859667 +162 169 -.5613809 +409 169 1 +410 169 -.0006471876 +163 170 -1 +164 170 -1 +165 170 -1 +410 170 1 +412 170 -1 +423 170 .06144421 +435 170 .0204814 +157 171 -1 +163 171 4124.06 +164 171 4124.06 +165 171 4124.06 +411 171 1 +413 171 -316220 +416 171 -20034.24 +417 171 -1 +423 171 -2625.657 +434 171 222.129 +412 172 18.73727 +414 172 .9448816 +413 173 1494.367 +414 173 -1.02078 +158 174 -.9918601 +163 174 -17.92234 +164 174 -17.92234 +165 174 -17.92234 +414 174 .862829 +415 174 1.049719 +423 174 -.7341495 +157 175 .00813986 +415 175 -222.129 +417 175 .00813986 +433 175 -222.129 +434 175 -1.808099 +163 176 -1.091328 +164 176 -1.629397 +165 176 -1.444853 +416 176 1 +423 176 .04736406 +435 176 -.02789814 +417 177 .004538534 +423 177 7.57924 +435 177 2.526413 +148 178 -1 +178 178 -1 +149 179 -1 +179 179 -1 +150 180 -1 +180 180 -1 +148 181 1.026646 +166 181 -1 +149 182 1.073724 +167 182 -1 +150 183 1.208147 +168 183 -1 +148 184 -1 +154 184 -1 +149 185 -1 +155 185 -1 +150 186 -1 +156 186 -1 +215 187 99.14973 +221 187 -1 +224 187 -3.311398e-5 +216 188 172.6396 +222 188 -1 +225 188 -4.110812e-5 +217 189 356.6398 +223 189 -1 +226 189 -8.458718e-5 +218 190 200.0008 +221 190 2.5 +224 190 3.311398e-5 +219 191 349.0033 +222 191 2.5 +225 191 4.110812e-5 +220 192 722.0678 +223 192 2.5 +226 192 8.458718e-5 +194 193 -.1148388 +221 193 1 +230 193 -.01164592 +195 194 -.4167839 +222 194 1 +230 194 -.1700616 +196 195 -.4967614 +223 195 1 +230 195 -.2436893 +197 196 -5276.862 +224 196 1.005025 +231 196 -.1956447 +198 197 -4241.591 +225 197 1.002874 +231 197 -.4983016 +199 198 -2058.294 +226 198 1.001387 +231 198 -.3060537 +194 199 -.3987228 +195 199 -.09909709 +227 199 1 +230 199 -.08086976 +194 200 -.4864384 +196 200 -.1005598 +228 200 1 +230 200 -.09866041 +195 201 -.484119 +196 201 -.4026788 +229 201 1 +230 201 -.395073 +197 202 -1 +198 202 -1 +199 202 -1 +230 202 1 +232 202 -1 +191 203 -1 +197 203 3297.623 +198 203 3297.623 +199 203 3297.623 +231 203 1 +233 203 -316220 +236 203 -18966.66 +237 203 -1 +232 204 22.66987 +234 204 .9548602 +233 205 2248.706 +234 205 -1.020655 +192 206 -.9922951 +197 206 -21.89857 +198 206 -21.89857 +199 206 -21.89857 +234 206 .8900096 +235 206 1.039205 +191 207 .007704897 +235 207 -146.1362 +237 207 .007704897 +197 208 -.6589052 +198 208 -1.106497 +199 208 -1.000909 +236 208 1 +237 209 .006895657 +182 210 -1 +212 210 -1 +183 211 -1 +213 211 -1 +184 212 -1 +214 212 -1 +182 213 1 +200 213 -1 +183 214 1.022676 +201 214 -1 +184 215 1.091418 +202 215 -1 +182 216 -1 +188 216 -1 +183 217 -1 +189 217 -1 +184 218 -1 +190 218 -1 +241 219 -.1996961 +242 219 -.7859616 +243 219 -.0006412823 +244 219 .4069041 +253 219 .2024702 +254 219 .7968796 +255 219 .0006501906 +256 219 -2.166544 +257 220 -1 +264 220 -.300015 +265 220 -.4074615 +246 221 -1 +247 221 -1 +258 221 1 +244 222 .4069041 +256 222 -2.166544 +264 222 1 +265 223 1 +238 224 0 +241 224 -.9862989 +250 224 -1 +253 224 1 +261 224 1 +264 224 3.501858 +265 224 1.241884 +239 225 0 +242 225 -.9862989 +251 225 -1 +254 225 1 +261 225 1 +264 225 -2.149559 +265 225 .9360239 +240 226 0 +243 226 -.9862989 +252 226 -1 +255 226 1 +261 226 1 +264 226 6.025986 +265 226 4.086838 +253 227 .0119553 +254 227 .6147503 +255 227 .1605955 +256 227 .599181 +275 227 -.01194968 +276 227 -.6144612 +277 227 -.16052 +278 227 -1 +257 228 1 +262 228 -.09335086 +263 228 -.3468181 +266 228 -1 +267 228 -1 +268 228 -1 +259 229 1 +256 230 -.599181 +262 230 1 +278 230 1 +263 231 1 +250 232 13.33342 +253 232 .7873011 +260 232 1 +262 232 12.12026 +263 232 .7702509 +275 232 -.7869309 +251 233 1.020551 +254 233 .7873011 +260 233 1 +262 233 -3.984399 +263 233 .681342 +276 233 -.7869309 +252 234 .003187485 +255 234 .7873011 +260 234 1 +262 234 19.25216 +263 234 2.236907 +277 234 -.7869309 +253 235 -.1700813 +254 235 -.8296922 +255 235 -.0006970141 +256 235 2.567363 +275 235 .1700014 +276 235 .829302 +277 235 .0006966863 +278 235 -4.284787 +279 236 -1 +286 236 -.2554693 +287 236 -.4122457 +258 237 -1 +259 237 -1 +280 237 1 +256 238 2.567363 +278 238 -4.284787 +286 238 1 +287 239 1 +250 240 0 +253 240 -1.000471 +272 240 -1 +275 240 1 +283 240 1 +286 240 2.955529 +287 240 1.254414 +251 241 0 +254 241 -1.000471 +273 241 -1 +276 241 1 +283 241 1 +286 241 -1.815969 +287 241 .9452119 +252 242 0 +255 242 -1.000471 +274 242 -1 +277 242 1 +283 242 1 +286 242 5.084997 +287 242 4.136479 +250 243 .2024702 +269 243 -1 +251 244 .7968796 +270 244 -1 +252 245 .2039823 +271 245 -1 +275 246 .009818081 +276 246 .6166417 +278 246 .9557944 +297 246 -.009817569 +298 246 -.6166096 +299 246 -.1605148 +300 246 -1 +279 247 1 +284 247 -.0982179 +285 247 -.3485639 +288 247 -1 +289 247 -1 +290 247 -1 +281 248 1 +278 249 -.9557944 +284 249 1 +300 249 1 +285 250 1 +272 251 13.62671 +275 251 .786983 +282 251 1 +284 251 12.68233 +285 251 .7694287 +297 251 -.786942 +273 252 1.058389 +276 252 .786983 +282 252 1 +284 252 -4.168489 +285 252 .6810285 +298 252 -.786942 +274 253 .003415583 +277 253 .786983 +282 253 1 +284 253 20.13996 +285 253 2.239415 +299 253 -.786942 +275 254 -.1678698 +276 254 -.8314825 +277 254 -.0006999047 +278 254 4.328993 +297 254 .167861 +298 254 .8314391 +299 254 .0006998682 +300 254 -4.529209 +301 255 -1 +308 255 -.2530153 +309 255 -.4125625 +280 256 -1 +281 256 -1 +302 256 1 +278 257 4.328993 +300 257 -4.529209 +308 257 1 +309 258 1 +272 259 0 +275 259 -1.000052 +294 259 -1 +297 259 1 +305 259 1 +308 259 2.925436 +309 259 1.255249 +273 260 0 +276 260 -1.000052 +295 260 -1 +298 260 1 +305 260 1 +308 260 -1.797593 +309 260 .9458243 +274 261 0 +277 261 -1.000052 +296 261 -1 +299 261 1 +305 261 1 +308 261 5.033166 +309 261 4.139783 +272 262 .1700014 +291 262 -1 +273 263 .829302 +292 263 -1 +274 264 .2039729 +293 264 -1 +297 265 .00967985 +298 265 .6167109 +299 265 .1605181 +300 265 .9972984 +319 265 -.00968017 +320 265 -.6167313 +321 265 -.1605234 +322 265 -1 +301 266 1 +306 266 -.09852872 +307 266 -.348671 +310 266 -1 +311 266 -1 +312 266 -1 +303 267 1 +300 268 -.9972984 +306 268 1 +322 268 1 +307 269 1 +294 270 13.64601 +297 270 .7869089 +304 270 1 +306 270 12.71619 +307 270 .7693586 +319 270 -.7869349 +295 271 1.060897 +298 271 .7869089 +304 271 1 +306 271 -4.179575 +307 271 .6809936 +320 271 -.7869349 +296 272 .003430968 +299 272 .7869089 +304 272 1 +306 272 20.19341 +307 272 2.239532 +321 272 -.7869349 +297 273 -.1677233 +298 273 -.8315405 +299 273 -.0007031113 +300 273 4.531911 +319 273 .1677288 +320 273 .831568 +321 273 .0007031346 +322 273 -4.544188 +323 274 -1 +330 274 -.2528891 +331 274 -.412629 +302 275 -1 +303 275 -1 +324 275 1 +300 276 4.531911 +322 276 -4.544188 +330 276 1 +331 277 1 +294 278 0 +297 278 -.9999669 +316 278 -1 +319 278 1 +327 278 1 +330 278 2.92357 +331 278 1.255294 +295 279 0 +298 279 -.9999669 +317 279 -1 +320 279 1 +327 279 1 +330 279 -1.79649 +331 279 .9458516 +296 280 0 +299 280 -.9999669 +318 280 -1 +321 280 1 +327 280 1 +330 280 5.029935 +331 280 4.14014 +294 281 .167861 +313 281 -1 +295 282 .8314391 +314 282 -1 +296 283 .2039856 +315 283 -1 +319 284 .00964735 +320 284 .6149968 +321 284 .1606638 +322 284 1.012275 +341 284 -.009663071 +342 284 -.615999 +343 284 -.1609257 +344 284 -1 +323 285 1 +328 285 -.09774015 +329 285 -.348389 +332 285 -1 +333 285 -1 +334 285 -1 +325 286 1 +322 287 -1.012275 +328 287 1 +344 287 1 +329 288 1 +316 289 13.65337 +319 289 .785308 +326 289 1 +328 289 12.53604 +329 289 .7686138 +341 289 -.7865877 +317 290 1.061854 +320 290 .785308 +326 290 1 +328 290 -4.120345 +329 290 .6803446 +342 290 -.7865877 +318 291 .003436848 +321 291 .785308 +326 291 1 +328 291 19.9072 +329 291 2.237486 +343 291 -.7865877 +319 292 -.167696 +320 292 -.8298335 +321 292 -.0008435821 +322 292 4.531913 +341 292 .1679693 +342 292 .8311858 +343 292 .0008449567 +344 292 -4.476957 +345 293 -1 +352 293 -.2542282 +353 293 -.4146785 +324 294 -1 +325 294 -1 +346 294 1 +322 295 4.531912 +344 295 -4.476957 +352 295 1 +353 296 1 +316 297 0 +319 297 -.9983731 +338 297 -1 +341 297 1 +349 297 1 +352 297 2.9258 +353 297 1.254871 +317 298 0 +320 298 -.9983731 +339 298 -1 +342 298 1 +349 298 1 +352 298 -1.799474 +353 298 .9452959 +318 299 0 +321 299 -.9983731 +340 299 -1 +343 299 1 +349 299 1 +352 299 5.032978 +353 299 4.146532 +316 300 .1677288 +335 300 -1 +317 301 .831568 +336 301 -1 +318 302 .204587 +337 302 -1 +341 303 .008958003 +342 303 .5623915 +343 303 .1714316 +344 303 1.534987 +363 303 -.009368401 +364 303 -.5881567 +365 303 -.1792855 +366 303 -1 +345 304 1 +350 304 -.07642457 +351 304 -.336307 +354 304 -1 +355 304 -1 +356 304 -1 +347 305 1 +344 306 -1.534987 +350 306 1 +366 306 1 +351 307 1 +338 308 13.9277 +341 308 .7427812 +348 308 1 +350 308 7.712414 +351 308 .7375405 +363 308 -.7768106 +339 309 1.097792 +342 309 .7427812 +348 309 1 +350 309 -2.534534 +351 309 .653208 +364 309 -.7768106 +340 310 .00366104 +343 310 .7427812 +348 310 1 +350 310 12.24449 +351 310 2.151386 +365 310 -.7768106 +341 311 -.1672642 +342 311 -.7775783 +343 311 -.01135093 +344 311 3.941971 +363 311 .1749272 +364 311 .8132019 +365 311 .01187095 +366 311 -2.568082 +367 312 -1 +374 312 -.3113227 +375 312 -.4557268 +346 313 -1 +347 313 -1 +368 313 1 +344 314 3.941971 +366 314 -2.568082 +374 314 1 +375 315 1 +338 316 0 +341 316 -.9561935 +360 316 -1 +363 316 1 +371 316 1 +374 316 3.149454 +375 316 1.212998 +339 317 0 +342 317 -.9561935 +361 317 -1 +364 317 1 +371 317 1 +374 317 -1.985919 +375 317 .9070684 +340 318 0 +343 318 -.9561935 +362 318 -1 +365 318 1 +371 318 1 +374 318 5.393687 +375 318 4.227463 +338 319 .1679693 +357 319 -1 +339 320 .8311858 +358 320 -1 +340 321 .2307969 +359 321 -1 +363 322 .004956003 +364 322 .2092511 +365 322 .4341566 +366 322 6.177384 +385 322 -.005686404 +386 322 -.2400899 +387 322 -.4981413 +388 322 -1 +367 323 1 +372 323 -.05189959 +373 323 -.2281993 +376 323 -1 +377 323 -1 +378 323 -1 +369 324 1 +366 325 -6.177384 +372 325 1 +388 325 1 +373 326 1 +360 327 22.88466 +363 327 .6483637 +370 327 1 +372 327 1.04345 +373 327 .4217586 +385 327 -.7439176 +361 328 2.519703 +364 328 .6483637 +370 328 1 +372 328 -.3414664 +373 328 .3798898 +386 328 -.7439176 +362 329 .01772792 +365 329 .6483637 +370 329 1 +372 329 1.646052 +373 329 1.305476 +387 329 -.7439176 +360 330 .1749272 +379 330 -1 +361 331 .8132019 +380 331 -1 +362 332 .669619 +381 332 -1 +87 333 6.318058 +93 333 1.008121 +88 334 2.101652 +94 334 .98325 +89 335 10.21634 +95 335 .971122 +90 336 4.771533 +96 336 1.016897 +91 337 1.544553 +97 337 .965152 +92 338 7.403258 +98 338 .9399198 +99 339 276.7648 +105 339 .8877067 +100 340 192.1904 +106 340 1.262063 +101 341 465.2974 +107 341 .8373005 +102 342 402.6353 +108 342 .9327234 +103 343 243.9516 +109 343 1.157006 +104 344 694.4257 +110 344 .9025243 +111 345 2.147169 +117 345 .7331041 +112 346 1.830354 +118 346 .7707069 +113 347 5.419496 +119 347 .9106797 +114 348 1.59346 +120 348 .4447283 +115 349 1.519359 +121 349 .5229601 +116 350 5.927271 +122 350 .8141707 +123 351 8.601323 +129 351 .5817151 +124 352 6.197485 +130 352 .5322072 +125 353 37.67033 +131 353 1.16833 +126 354 10.95535 +132 354 .7493993 +127 355 8.286427 +133 355 .7197383 +128 356 35.09293 +134 356 1.100849 +135 357 .4338919 +138 357 2.279713 +136 358 .1137572 +139 358 .6069821 +137 359 .4035473 +140 359 .008004989 +141 360 1.157704 +144 360 4.042228 +142 361 .4193259 +145 361 2.449611 +143 362 .1024647 +146 362 .3647518 +151 363 172.5745 +154 363 14.91761 +152 364 161.5845 +155 364 12.0938 +153 365 145.3145 +156 365 5.740096 +157 366 .004501889 +158 366 .9526359 +159 366 -1 +158 367 .9448816 +163 367 19.88206 +164 367 15.9987 +165 367 7.769499 +159 368 1.00814 +163 368 98.82898 +164 368 147.5558 +165 368 130.8437 +160 369 1 +163 369 1.801198 +161 370 1 +164 370 2.196221 +162 371 1 +165 371 2.060738 +163 372 19.88206 +166 372 .9740453 +164 373 15.9987 +167 373 .9313378 +165 374 7.769499 +168 374 .827714 +169 375 -1 +172 375 -1 +175 375 .05635791 +176 375 .05635791 +177 375 .05635791 +170 376 -1 +173 376 -1 +175 376 .7395973 +176 376 .7395973 +177 376 .7395973 +171 377 -1 +174 377 -1 +175 377 .2040448 +176 377 .2040448 +177 377 .2040448 +172 378 1 +175 378 -1 +173 379 1 +176 379 -1 +174 380 1 +177 380 -1 +175 381 1 +178 381 1 +176 382 1 +179 382 1 +177 383 1 +180 383 1 +102 384 -19.45389 +418 384 1 +424 384 -.09530421 +103 385 -22.09031 +419 385 1 +424 385 -.08819762 +104 386 -49.56359 +420 386 1 +424 386 -.0001069042 +421 387 179.7345 +422 387 -2.59574 +422 388 1 +423 388 -.09621652 +102 389 -1 +103 389 -1 +104 389 -1 +423 389 .09621652 +424 389 -.008893728 +126 390 .9308279 +127 390 .9308279 +128 390 .9308279 +425 390 -1.138352 +436 390 .09534178 +126 391 .8176979 +426 391 -.5508352 +436 391 .04613478 +127 392 .8176979 +427 392 -.4489223 +436 392 .03759915 +128 393 6.806865 +428 393 -.002018842 +436 393 .0001690866 +429 394 -.6031359 +430 394 -1.191426 +431 394 -.2090101 +432 394 -.2323664 +126 395 -1.588199 +430 395 1 +436 395 -.08960673 +127 396 -1.789478 +431 396 1 +436 396 -.08228325 +128 397 -4.012804 +432 397 1 +436 397 -9.968042e-5 +433 398 1.186874 +435 398 -.8713432 +434 399 .9918601 +435 399 -.7341495 +126 400 -1 +127 400 -1 +128 400 -1 +435 400 .8978249 +436 400 -.1024269 +185 401 263.3025 +188 401 16.71023 +186 402 252.3125 +189 402 15.09138 +187 403 236.0425 +190 403 11.44029 +191 404 .006842933 +192 404 .9622744 +193 404 -1 +192 405 .9548602 +197 405 35.04212 +198 405 28.16719 +199 405 13.66854 +193 406 1.007705 +197 406 85.84676 +198 406 144.1621 +199 406 130.4054 +194 407 1 +197 407 1.658905 +195 408 1 +198 408 2.106497 +196 409 1 +199 409 2.000909 +197 410 35.04212 +200 410 1 +198 411 28.16719 +201 411 .9778269 +199 412 13.66854 +202 412 .9162394 +203 413 -1 +206 413 -1 +209 413 .00343519 +210 413 .00343519 +211 413 .00343519 +204 414 -1 +207 414 -1 +209 414 .04301697 +210 414 .04301697 +211 414 .04301697 +205 415 -1 +208 415 -1 +209 415 .9535478 +210 415 .9535478 +211 415 .9535478 +206 416 1 +209 416 -1 +207 417 1 +210 417 -1 +208 418 1 +211 418 -1 +209 419 1 +212 419 1 +210 420 1 +213 420 1 +211 421 1 +214 421 1 +90 422 -.04761313 +461 422 1 +467 422 -2.33347e-5 +91 423 -.05746435 +462 423 1 +467 423 -.0003526656 +92 424 -.1295604 +463 424 1 +467 424 -.01762542 +464 425 270.4625 +465 425 -2.800067 +465 426 1 +466 426 -1.685693 +90 427 -1 +91 427 -1 +92 427 -1 +466 427 1.685693 +467 427 -.1426674 +114 428 .1214974 +115 428 .1214974 +116 428 .1214974 +468 428 -1.138352 +479 428 .02123052 +114 429 .6055575 +469 429 -.01949018 +479 429 .0003634963 +115 430 .3357927 +470 430 -.1353383 +479 430 .00252409 +116 431 .1067309 +471 431 -.9535478 +479 431 .01778388 +472 432 -.9075922 +473 432 -5.711822 +474 432 -.9356841 +475 432 -1.034655 +114 433 -.04324093 +473 433 1 +479 433 -2.595611e-5 +115 434 -.05217491 +474 434 1 +479 434 -.000392189 +116 435 -.1176314 +475 435 1 +479 435 -.01960016 +476 436 5.314078 +478 436 -1.002184 +477 437 .3448372 +478 437 -.2647862 +114 438 -1 +115 438 -1 +116 438 -1 +478 438 1.766971 +479 438 -.1747406 +438 439 99.14973 +444 439 -1 +447 439 -3.311398e-5 +439 440 172.6396 +445 440 -1 +448 440 -4.110812e-5 +440 441 356.6398 +446 441 -1 +449 441 -8.458718e-5 +441 442 200.0008 +444 442 2.5 +447 442 3.311398e-5 +442 443 349.0033 +445 443 2.5 +448 443 4.110812e-5 +443 444 722.0678 +446 444 2.5 +449 444 8.458718e-5 +444 445 1 +453 445 -1.448565e-6 +445 446 1 +453 446 -.0005113292 +446 447 1 +453 447 -.9543887 +447 448 1.005025 +454 448 -.00343519 +448 449 1.002874 +454 449 -.04301697 +449 450 1.001387 +454 450 -.9535478 +450 451 1 +453 451 -4.94556e-5 +451 452 1 +453 452 -.002177557 +452 453 1 +453 453 -.04287153 +453 454 1 +455 454 -1 +466 454 1.5 +478 454 .5 +454 455 1 +456 455 -316220 +459 455 -12132.58 +460 455 -1 +466 455 -20451.81 +477 455 9152.751 +455 456 9.146357 +457 456 .003773492 +456 457 2248.706 +457 457 -.1250533 +457 458 .06758838 +458 458 65.08712 +466 458 -.1885904 +458 459 -9152.751 +460 459 .7543943 +476 459 -9152.751 +477 459 -6904.783 +459 460 1 +466 460 .1856929 +478 460 -.5 +460 461 .0001916794 +466 461 2.668452 +478 461 .889484 +266 462 .523971 +269 462 2.590273 +267 463 .1209036 +270 463 1 +268 464 .3660773 +271 464 .01832333 +288 465 .5307083 +291 465 2.612032 +289 466 .1214381 +292 466 1 +290 467 .3632748 +293 467 .01939848 +310 468 .5311485 +313 468 2.613447 +311 469 .1214731 +314 469 1 +312 470 .3630917 +315 470 .01947045 +332 471 .5313162 +335 471 2.613986 +333 472 .1214864 +336 472 1 +334 473 .3630219 +337 473 .01949793 +354 474 .5375334 +357 474 2.63388 +355 475 .1219796 +358 475 1 +356 476 .3604358 +359 476 .02053846 +376 477 .7109283 +379 477 3.130467 +377 478 .1357358 +380 478 1 +378 479 .2883091 +381 479 .07148988 diff --git a/Source/Examples/ExampleLibrary/Series/AreaSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/AreaSeriesExamples.cs new file mode 100644 index 0000000..57d072c --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/AreaSeriesExamples.cs @@ -0,0 +1,454 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("AreaSeries"), Tags("Series")] + public static class AreaSeriesExamples + { + [Example("Default style")] + [DocumentationExample("Series/AreaSeries")] + public static PlotModel DefaultStyle() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with default style" }; + plotModel1.Series.Add(CreateExampleAreaSeries()); + return plotModel1; + } + + [Example("Different stroke colors")] + public static PlotModel DifferentColors() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with different stroke colors" }; + var areaSeries1 = CreateExampleAreaSeries(); + areaSeries1.Color = OxyColors.Red; + areaSeries1.Color2 = OxyColors.Blue; + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("Crossing lines")] + public static PlotModel CrossingLines() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with crossing lines" }; + var areaSeries1 = new AreaSeries(); + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 140)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + areaSeries1.Points2.Add(new DataPoint(0, 60)); + areaSeries1.Points2.Add(new DataPoint(5, 80)); + areaSeries1.Points2.Add(new DataPoint(20, 70)); + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("Custom TrackerFormatString")] + public static PlotModel TrackerFormatString() + { + var model = new PlotModel { Title = "AreaSeries with custom TrackerFormatString" }; + + // the axis titles will be used in the default tracker format string + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "X-axis" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Y-axis" }); + + var areaSeries1 = CreateExampleAreaSeries(); + areaSeries1.Title = "X={2:0.0} Y={4:0.0}"; + areaSeries1.TrackerFormatString = "X={2:0.0} Y={4:0.0}"; + model.Series.Add(areaSeries1); + return model; + } + + [Example("Constant baseline (empty Points2)")] + public static PlotModel ConstantBaseline() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with constant baseline", Subtitle = "Empty Points2, ConstantY2 = 0 (default)" }; + var areaSeries1 = new AreaSeries(); + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 140)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("Constant baseline (empty Points2, ConstantY2=NaN)")] + public static PlotModel ConstantBaselineNaN() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with constant baseline", Subtitle = "Empty Points2, ConstantY2 = NaN" }; + var areaSeries1 = new AreaSeries(); + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 140)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + areaSeries1.ConstantY2 = double.NaN; + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("Constant baseline (ItemsSource and DataField2 not set)")] + public static PlotModel ConstantBaselineItemsSource() + { + var plotModel1 = new PlotModel { Title = "AreaSeries with constant baseline", Subtitle = "ItemsSource and DataField2 not set, ConstantY2 = -20" }; + var areaSeries1 = new AreaSeries(); + var points = new[] { new DataPoint(0, 50), new DataPoint(10, 140), new DataPoint(20, 60) }; + areaSeries1.ItemsSource = points; + areaSeries1.DataFieldX = "X"; + areaSeries1.DataFieldY = "Y"; + areaSeries1.ConstantY2 = -20; + plotModel1.Series.Add(areaSeries1); + return plotModel1; + } + + [Example("LineSeries and AreaSeries")] + public static PlotModel LineSeriesAndAreaSeries() + { + var plotModel1 = new PlotModel { Title = "LineSeries and AreaSeries" }; + var linearAxis1 = new LinearAxis { Position = AxisPosition.Bottom }; + plotModel1.Axes.Add(linearAxis1); + var linearAxis2 = new LinearAxis(); + plotModel1.Axes.Add(linearAxis2); + var areaSeries1 = new AreaSeries + { + Fill = OxyColors.LightBlue, + DataFieldX2 = "Time", + DataFieldY2 = "Minimum", + Color = OxyColors.Red, + StrokeThickness = 0, + MarkerFill = OxyColors.Transparent, + DataFieldX = "Time", + DataFieldY = "Maximum" + }; + areaSeries1.Points2.Add(new DataPoint(0, -5.04135905692417)); + areaSeries1.Points2.Add(new DataPoint(2.5, -4.91731850813018)); + areaSeries1.Points2.Add(new DataPoint(5, -4.45266314658926)); + areaSeries1.Points2.Add(new DataPoint(7.5, -3.87303874542613)); + areaSeries1.Points2.Add(new DataPoint(10, -3.00101110255393)); + areaSeries1.Points2.Add(new DataPoint(12.5, -2.17980725503518)); + areaSeries1.Points2.Add(new DataPoint(15, -1.67332229254456)); + areaSeries1.Points2.Add(new DataPoint(17.5, -1.10537158549082)); + areaSeries1.Points2.Add(new DataPoint(20, -0.6145459544447)); + areaSeries1.Points2.Add(new DataPoint(22.5, 0.120028106039404)); + areaSeries1.Points2.Add(new DataPoint(25, 1.06357270435597)); + areaSeries1.Points2.Add(new DataPoint(27.5, 1.87301405606466)); + areaSeries1.Points2.Add(new DataPoint(30, 2.57569854952195)); + areaSeries1.Points2.Add(new DataPoint(32.5, 3.59165537664278)); + areaSeries1.Points2.Add(new DataPoint(35, 4.87991958133872)); + areaSeries1.Points2.Add(new DataPoint(37.5, 6.36214537958714)); + areaSeries1.Points2.Add(new DataPoint(40, 7.62564585126268)); + areaSeries1.Points2.Add(new DataPoint(42.5, 8.69606320261772)); + areaSeries1.Points2.Add(new DataPoint(45, 10.0118704438265)); + areaSeries1.Points2.Add(new DataPoint(47.5, 11.0434480519236)); + areaSeries1.Points2.Add(new DataPoint(50, 11.9794171576758)); + areaSeries1.Points2.Add(new DataPoint(52.5, 12.9591851832621)); + areaSeries1.Points2.Add(new DataPoint(55, 14.172107889304)); + areaSeries1.Points2.Add(new DataPoint(57.5, 15.5520057698488)); + areaSeries1.Points2.Add(new DataPoint(60, 17.2274942386092)); + areaSeries1.Points2.Add(new DataPoint(62.5, 18.6983982186757)); + areaSeries1.Points2.Add(new DataPoint(65, 20.4560332001448)); + areaSeries1.Points2.Add(new DataPoint(67.5, 22.4867327382261)); + areaSeries1.Points2.Add(new DataPoint(70, 24.5319674302041)); + areaSeries1.Points2.Add(new DataPoint(72.5, 26.600547815813)); + areaSeries1.Points2.Add(new DataPoint(75, 28.5210891459701)); + areaSeries1.Points2.Add(new DataPoint(77.5, 30.6793080755413)); + areaSeries1.Points2.Add(new DataPoint(80, 33.0546651200646)); + areaSeries1.Points2.Add(new DataPoint(82.5, 35.3256065179713)); + areaSeries1.Points2.Add(new DataPoint(85, 37.6336074839968)); + areaSeries1.Points2.Add(new DataPoint(87.5, 40.2012266359763)); + areaSeries1.Points2.Add(new DataPoint(90, 42.8923555399256)); + areaSeries1.Points2.Add(new DataPoint(92.5, 45.8665211907432)); + areaSeries1.Points2.Add(new DataPoint(95, 48.8200195945427)); + areaSeries1.Points2.Add(new DataPoint(97.5, 51.8304284402311)); + areaSeries1.Points2.Add(new DataPoint(100, 54.6969868542147)); + areaSeries1.Points2.Add(new DataPoint(102.5, 57.7047292990632)); + areaSeries1.Points2.Add(new DataPoint(105, 60.4216644602929)); + areaSeries1.Points2.Add(new DataPoint(107.5, 62.926258762519)); + areaSeries1.Points2.Add(new DataPoint(110, 65.1829734629407)); + areaSeries1.Points2.Add(new DataPoint(112.5, 67.2365592083133)); + areaSeries1.Points2.Add(new DataPoint(115, 69.5713628691022)); + areaSeries1.Points2.Add(new DataPoint(117.5, 71.7267046705944)); + areaSeries1.Points2.Add(new DataPoint(120, 73.633463102781)); + areaSeries1.Points2.Add(new DataPoint(122.5, 75.4660150158061)); + areaSeries1.Points2.Add(new DataPoint(125, 77.5669292504745)); + areaSeries1.Points2.Add(new DataPoint(127.5, 79.564218544664)); + areaSeries1.Points2.Add(new DataPoint(130, 81.8631309028078)); + areaSeries1.Points2.Add(new DataPoint(132.5, 83.9698189969034)); + areaSeries1.Points2.Add(new DataPoint(135, 86.3847886532009)); + areaSeries1.Points2.Add(new DataPoint(137.5, 88.5559348267764)); + areaSeries1.Points2.Add(new DataPoint(140, 91.0455050418365)); + areaSeries1.Points2.Add(new DataPoint(142.5, 93.6964157585504)); + areaSeries1.Points2.Add(new DataPoint(145, 96.284336864941)); + areaSeries1.Points2.Add(new DataPoint(147.5, 98.7508602689723)); + areaSeries1.Points2.Add(new DataPoint(150, 100.904510594255)); + areaSeries1.Points2.Add(new DataPoint(152.5, 103.266136681506)); + areaSeries1.Points2.Add(new DataPoint(155, 105.780951269521)); + areaSeries1.Points2.Add(new DataPoint(157.5, 108.032859257065)); + areaSeries1.Points2.Add(new DataPoint(160, 110.035478448093)); + areaSeries1.Points2.Add(new DataPoint(162.5, 112.10655731615)); + areaSeries1.Points2.Add(new DataPoint(165, 114.37480786097)); + areaSeries1.Points2.Add(new DataPoint(167.5, 116.403992550869)); + areaSeries1.Points2.Add(new DataPoint(170, 118.61663988727)); + areaSeries1.Points2.Add(new DataPoint(172.5, 120.538730287384)); + areaSeries1.Points2.Add(new DataPoint(175, 122.515721057177)); + areaSeries1.Points2.Add(new DataPoint(177.5, 124.474386629124)); + areaSeries1.Points2.Add(new DataPoint(180, 126.448283293214)); + areaSeries1.Points2.Add(new DataPoint(182.5, 128.373811322299)); + areaSeries1.Points2.Add(new DataPoint(185, 130.33627914667)); + areaSeries1.Points2.Add(new DataPoint(187.5, 132.487933658477)); + areaSeries1.Points2.Add(new DataPoint(190, 134.716989778456)); + areaSeries1.Points2.Add(new DataPoint(192.5, 136.817287595392)); + areaSeries1.Points2.Add(new DataPoint(195, 139.216488664698)); + areaSeries1.Points2.Add(new DataPoint(197.5, 141.50803227574)); + areaSeries1.Points2.Add(new DataPoint(200, 143.539586683614)); + areaSeries1.Points2.Add(new DataPoint(202.5, 145.535911545221)); + areaSeries1.Points2.Add(new DataPoint(205, 147.516964978686)); + areaSeries1.Points2.Add(new DataPoint(207.5, 149.592416731684)); + areaSeries1.Points2.Add(new DataPoint(210, 151.600983566512)); + areaSeries1.Points2.Add(new DataPoint(212.5, 153.498210993362)); + areaSeries1.Points2.Add(new DataPoint(215, 155.512606828247)); + areaSeries1.Points2.Add(new DataPoint(217.5, 157.426564302774)); + areaSeries1.Points2.Add(new DataPoint(220, 159.364474964172)); + areaSeries1.Points2.Add(new DataPoint(222.5, 161.152806492128)); + areaSeries1.Points2.Add(new DataPoint(225, 162.679069434562)); + areaSeries1.Points2.Add(new DataPoint(227.5, 163.893622036741)); + areaSeries1.Points2.Add(new DataPoint(230, 165.475827621238)); + areaSeries1.Points2.Add(new DataPoint(232.5, 167.303960444734)); + areaSeries1.Points2.Add(new DataPoint(235, 169.259393394952)); + areaSeries1.Points2.Add(new DataPoint(237.5, 171.265193646758)); + areaSeries1.Points2.Add(new DataPoint(240, 173.074304345192)); + areaSeries1.Points2.Add(new DataPoint(242.5, 174.975492766814)); + areaSeries1.Points2.Add(new DataPoint(245, 176.684088218484)); + areaSeries1.Points2.Add(new DataPoint(247.5, 178.406887247603)); + areaSeries1.Points.Add(new DataPoint(0, 5.0184649433561)); + areaSeries1.Points.Add(new DataPoint(2.5, 5.27685959268215)); + areaSeries1.Points.Add(new DataPoint(5, 5.81437064628786)); + areaSeries1.Points.Add(new DataPoint(7.5, 6.51022475040994)); + areaSeries1.Points.Add(new DataPoint(10, 7.49921246878766)); + areaSeries1.Points.Add(new DataPoint(12.5, 8.41941631823751)); + areaSeries1.Points.Add(new DataPoint(15, 9.09826907222079)); + areaSeries1.Points.Add(new DataPoint(17.5, 9.89500750098145)); + areaSeries1.Points.Add(new DataPoint(20, 10.6633345249404)); + areaSeries1.Points.Add(new DataPoint(22.5, 11.6249613445368)); + areaSeries1.Points.Add(new DataPoint(25, 12.8816391467497)); + areaSeries1.Points.Add(new DataPoint(27.5, 13.9665185705603)); + areaSeries1.Points.Add(new DataPoint(30, 14.8501816818724)); + areaSeries1.Points.Add(new DataPoint(32.5, 16.0683128022441)); + areaSeries1.Points.Add(new DataPoint(35, 17.5378799723172)); + areaSeries1.Points.Add(new DataPoint(37.5, 19.1262752954039)); + areaSeries1.Points.Add(new DataPoint(40, 20.4103953650735)); + areaSeries1.Points.Add(new DataPoint(42.5, 21.5430627723891)); + areaSeries1.Points.Add(new DataPoint(45, 22.9105459463366)); + areaSeries1.Points.Add(new DataPoint(47.5, 23.9802361888719)); + areaSeries1.Points.Add(new DataPoint(50, 24.8659461235003)); + areaSeries1.Points.Add(new DataPoint(52.5, 25.7303194442439)); + areaSeries1.Points.Add(new DataPoint(55, 26.7688545912359)); + areaSeries1.Points.Add(new DataPoint(57.5, 28.0545112571933)); + areaSeries1.Points.Add(new DataPoint(60, 29.7036634266394)); + areaSeries1.Points.Add(new DataPoint(62.5, 31.2273634344467)); + areaSeries1.Points.Add(new DataPoint(65, 33.1038196356519)); + areaSeries1.Points.Add(new DataPoint(67.5, 35.2639893610328)); + areaSeries1.Points.Add(new DataPoint(70, 37.434293559489)); + areaSeries1.Points.Add(new DataPoint(72.5, 39.7109359368267)); + areaSeries1.Points.Add(new DataPoint(75, 41.7573881676222)); + areaSeries1.Points.Add(new DataPoint(77.5, 44.0460374479862)); + areaSeries1.Points.Add(new DataPoint(80, 46.5098714746581)); + areaSeries1.Points.Add(new DataPoint(82.5, 48.7754012129155)); + areaSeries1.Points.Add(new DataPoint(85, 51.1619816926597)); + areaSeries1.Points.Add(new DataPoint(87.5, 53.9036778414639)); + areaSeries1.Points.Add(new DataPoint(90, 56.7448825012636)); + areaSeries1.Points.Add(new DataPoint(92.5, 59.9294987878434)); + areaSeries1.Points.Add(new DataPoint(95, 63.0148831289797)); + areaSeries1.Points.Add(new DataPoint(97.5, 66.0721745989622)); + areaSeries1.Points.Add(new DataPoint(100, 68.8980036274521)); + areaSeries1.Points.Add(new DataPoint(102.5, 71.7719322611447)); + areaSeries1.Points.Add(new DataPoint(105, 74.4206055336728)); + areaSeries1.Points.Add(new DataPoint(107.5, 76.816198386632)); + areaSeries1.Points.Add(new DataPoint(110, 79.0040432726983)); + areaSeries1.Points.Add(new DataPoint(112.5, 80.9617606926066)); + areaSeries1.Points.Add(new DataPoint(115, 83.1345574620341)); + areaSeries1.Points.Add(new DataPoint(117.5, 85.0701022046479)); + areaSeries1.Points.Add(new DataPoint(120, 86.8557530286516)); + areaSeries1.Points.Add(new DataPoint(122.5, 88.5673387745243)); + areaSeries1.Points.Add(new DataPoint(125, 90.6003321543338)); + areaSeries1.Points.Add(new DataPoint(127.5, 92.439864576254)); + areaSeries1.Points.Add(new DataPoint(130, 94.5383744861178)); + areaSeries1.Points.Add(new DataPoint(132.5, 96.4600166864507)); + areaSeries1.Points.Add(new DataPoint(135, 98.6091052949006)); + areaSeries1.Points.Add(new DataPoint(137.5, 100.496459351478)); + areaSeries1.Points.Add(new DataPoint(140, 102.705767030085)); + areaSeries1.Points.Add(new DataPoint(142.5, 105.009994476992)); + areaSeries1.Points.Add(new DataPoint(145, 107.31287026052)); + areaSeries1.Points.Add(new DataPoint(147.5, 109.584842542272)); + areaSeries1.Points.Add(new DataPoint(150, 111.641435600837)); + areaSeries1.Points.Add(new DataPoint(152.5, 113.988459973544)); + areaSeries1.Points.Add(new DataPoint(155, 116.50349048027)); + areaSeries1.Points.Add(new DataPoint(157.5, 118.753612704274)); + areaSeries1.Points.Add(new DataPoint(160, 120.801728924085)); + areaSeries1.Points.Add(new DataPoint(162.5, 122.902486914165)); + areaSeries1.Points.Add(new DataPoint(165, 125.104391935796)); + areaSeries1.Points.Add(new DataPoint(167.5, 127.06056966547)); + areaSeries1.Points.Add(new DataPoint(170, 129.217086578495)); + areaSeries1.Points.Add(new DataPoint(172.5, 131.151968896274)); + areaSeries1.Points.Add(new DataPoint(175, 133.159906275133)); + areaSeries1.Points.Add(new DataPoint(177.5, 135.065263957561)); + areaSeries1.Points.Add(new DataPoint(180, 137.041870026822)); + areaSeries1.Points.Add(new DataPoint(182.5, 138.937477489811)); + areaSeries1.Points.Add(new DataPoint(185, 140.776914926282)); + areaSeries1.Points.Add(new DataPoint(187.5, 142.786975776398)); + areaSeries1.Points.Add(new DataPoint(190, 144.862762377347)); + areaSeries1.Points.Add(new DataPoint(192.5, 146.89654967049)); + areaSeries1.Points.Add(new DataPoint(195, 149.204343821204)); + areaSeries1.Points.Add(new DataPoint(197.5, 151.369748673527)); + areaSeries1.Points.Add(new DataPoint(200, 153.324438580137)); + areaSeries1.Points.Add(new DataPoint(202.5, 155.173148715344)); + areaSeries1.Points.Add(new DataPoint(205, 157.0501827528)); + areaSeries1.Points.Add(new DataPoint(207.5, 159.109122278359)); + areaSeries1.Points.Add(new DataPoint(210, 161.044446932778)); + areaSeries1.Points.Add(new DataPoint(212.5, 162.942364031841)); + areaSeries1.Points.Add(new DataPoint(215, 164.966769883021)); + areaSeries1.Points.Add(new DataPoint(217.5, 166.89711806788)); + areaSeries1.Points.Add(new DataPoint(220, 168.906874949069)); + areaSeries1.Points.Add(new DataPoint(222.5, 170.85692034995)); + areaSeries1.Points.Add(new DataPoint(225, 172.602125010408)); + areaSeries1.Points.Add(new DataPoint(227.5, 173.964258466598)); + areaSeries1.Points.Add(new DataPoint(230, 175.629908385654)); + areaSeries1.Points.Add(new DataPoint(232.5, 177.495778359378)); + areaSeries1.Points.Add(new DataPoint(235, 179.432933300749)); + areaSeries1.Points.Add(new DataPoint(237.5, 181.400180771342)); + areaSeries1.Points.Add(new DataPoint(240, 183.232300309899)); + areaSeries1.Points.Add(new DataPoint(242.5, 185.225502661441)); + areaSeries1.Points.Add(new DataPoint(245, 186.979590140413)); + areaSeries1.Points.Add(new DataPoint(247.5, 188.816640077725)); + areaSeries1.Title = "Maximum/Minimum"; + plotModel1.Series.Add(areaSeries1); + + var lineSeries1 = new LineSeries + { + Color = OxyColors.Blue, + MarkerFill = OxyColors.Transparent, + DataFieldX = "Time", + DataFieldY = "Value" + }; + lineSeries1.Points.Add(new DataPoint(0, -0.011447056784037)); + lineSeries1.Points.Add(new DataPoint(2.5, 0.179770542275985)); + lineSeries1.Points.Add(new DataPoint(5, 0.6808537498493)); + lineSeries1.Points.Add(new DataPoint(7.5, 1.31859300249191)); + lineSeries1.Points.Add(new DataPoint(10, 2.24910068311687)); + lineSeries1.Points.Add(new DataPoint(12.5, 3.11980453160117)); + lineSeries1.Points.Add(new DataPoint(15, 3.71247338983811)); + lineSeries1.Points.Add(new DataPoint(17.5, 4.39481795774531)); + lineSeries1.Points.Add(new DataPoint(20, 5.02439428524784)); + lineSeries1.Points.Add(new DataPoint(22.5, 5.87249472528812)); + lineSeries1.Points.Add(new DataPoint(25, 6.97260592555283)); + lineSeries1.Points.Add(new DataPoint(27.5, 7.91976631331247)); + lineSeries1.Points.Add(new DataPoint(30, 8.71294011569719)); + lineSeries1.Points.Add(new DataPoint(32.5, 9.82998408944345)); + lineSeries1.Points.Add(new DataPoint(35, 11.208899776828)); + lineSeries1.Points.Add(new DataPoint(37.5, 12.7442103374955)); + lineSeries1.Points.Add(new DataPoint(40, 14.0180206081681)); + lineSeries1.Points.Add(new DataPoint(42.5, 15.1195629875034)); + lineSeries1.Points.Add(new DataPoint(45, 16.4612081950815)); + lineSeries1.Points.Add(new DataPoint(47.5, 17.5118421203978)); + lineSeries1.Points.Add(new DataPoint(50, 18.4226816405881)); + lineSeries1.Points.Add(new DataPoint(52.5, 19.344752313753)); + lineSeries1.Points.Add(new DataPoint(55, 20.47048124027)); + lineSeries1.Points.Add(new DataPoint(57.5, 21.8032585135211)); + lineSeries1.Points.Add(new DataPoint(60, 23.4655788326243)); + lineSeries1.Points.Add(new DataPoint(62.5, 24.9628808265612)); + lineSeries1.Points.Add(new DataPoint(65, 26.7799264178984)); + lineSeries1.Points.Add(new DataPoint(67.5, 28.8753610496295)); + lineSeries1.Points.Add(new DataPoint(70, 30.9831304948466)); + lineSeries1.Points.Add(new DataPoint(72.5, 33.1557418763199)); + lineSeries1.Points.Add(new DataPoint(75, 35.1392386567962)); + lineSeries1.Points.Add(new DataPoint(77.5, 37.3626727617638)); + lineSeries1.Points.Add(new DataPoint(80, 39.7822682973613)); + lineSeries1.Points.Add(new DataPoint(82.5, 42.0505038654434)); + lineSeries1.Points.Add(new DataPoint(85, 44.3977945883283)); + lineSeries1.Points.Add(new DataPoint(87.5, 47.0524522387201)); + lineSeries1.Points.Add(new DataPoint(90, 49.8186190205946)); + lineSeries1.Points.Add(new DataPoint(92.5, 52.8980099892933)); + lineSeries1.Points.Add(new DataPoint(95, 55.9174513617612)); + lineSeries1.Points.Add(new DataPoint(97.5, 58.9513015195966)); + lineSeries1.Points.Add(new DataPoint(100, 61.7974952408334)); + lineSeries1.Points.Add(new DataPoint(102.5, 64.738330780104)); + lineSeries1.Points.Add(new DataPoint(105, 67.4211349969828)); + lineSeries1.Points.Add(new DataPoint(107.5, 69.8712285745755)); + lineSeries1.Points.Add(new DataPoint(110, 72.0935083678195)); + lineSeries1.Points.Add(new DataPoint(112.5, 74.0991599504599)); + lineSeries1.Points.Add(new DataPoint(115, 76.3529601655682)); + lineSeries1.Points.Add(new DataPoint(117.5, 78.3984034376212)); + lineSeries1.Points.Add(new DataPoint(120, 80.2446080657163)); + lineSeries1.Points.Add(new DataPoint(122.5, 82.0166768951652)); + lineSeries1.Points.Add(new DataPoint(125, 84.0836307024042)); + lineSeries1.Points.Add(new DataPoint(127.5, 86.002041560459)); + lineSeries1.Points.Add(new DataPoint(130, 88.2007526944628)); + lineSeries1.Points.Add(new DataPoint(132.5, 90.2149178416771)); + lineSeries1.Points.Add(new DataPoint(135, 92.4969469740507)); + lineSeries1.Points.Add(new DataPoint(137.5, 94.5261970891274)); + lineSeries1.Points.Add(new DataPoint(140, 96.875636035961)); + lineSeries1.Points.Add(new DataPoint(142.5, 99.3532051177711)); + lineSeries1.Points.Add(new DataPoint(145, 101.798603562731)); + lineSeries1.Points.Add(new DataPoint(147.5, 104.167851405622)); + lineSeries1.Points.Add(new DataPoint(150, 106.272973097546)); + lineSeries1.Points.Add(new DataPoint(152.5, 108.627298327525)); + lineSeries1.Points.Add(new DataPoint(155, 111.142220874895)); + lineSeries1.Points.Add(new DataPoint(157.5, 113.39323598067)); + lineSeries1.Points.Add(new DataPoint(160, 115.418603686089)); + lineSeries1.Points.Add(new DataPoint(162.5, 117.504522115157)); + lineSeries1.Points.Add(new DataPoint(165, 119.739599898383)); + lineSeries1.Points.Add(new DataPoint(167.5, 121.732281108169)); + lineSeries1.Points.Add(new DataPoint(170, 123.916863232882)); + lineSeries1.Points.Add(new DataPoint(172.5, 125.845349591829)); + lineSeries1.Points.Add(new DataPoint(175, 127.837813666155)); + lineSeries1.Points.Add(new DataPoint(177.5, 129.769825293343)); + lineSeries1.Points.Add(new DataPoint(180, 131.745076660018)); + lineSeries1.Points.Add(new DataPoint(182.5, 133.655644406055)); + lineSeries1.Points.Add(new DataPoint(185, 135.556597036476)); + lineSeries1.Points.Add(new DataPoint(187.5, 137.637454717438)); + lineSeries1.Points.Add(new DataPoint(190, 139.789876077902)); + lineSeries1.Points.Add(new DataPoint(192.5, 141.856918632941)); + lineSeries1.Points.Add(new DataPoint(195, 144.210416242951)); + lineSeries1.Points.Add(new DataPoint(197.5, 146.438890474634)); + lineSeries1.Points.Add(new DataPoint(200, 148.432012631876)); + lineSeries1.Points.Add(new DataPoint(202.5, 150.354530130282)); + lineSeries1.Points.Add(new DataPoint(205, 152.283573865743)); + lineSeries1.Points.Add(new DataPoint(207.5, 154.350769505022)); + lineSeries1.Points.Add(new DataPoint(210, 156.322715249645)); + lineSeries1.Points.Add(new DataPoint(212.5, 158.220287512602)); + lineSeries1.Points.Add(new DataPoint(215, 160.239688355634)); + lineSeries1.Points.Add(new DataPoint(217.5, 162.161841185327)); + lineSeries1.Points.Add(new DataPoint(220, 164.135674956621)); + lineSeries1.Points.Add(new DataPoint(222.5, 166.004863421039)); + lineSeries1.Points.Add(new DataPoint(225, 167.640597222485)); + lineSeries1.Points.Add(new DataPoint(227.5, 168.928940251669)); + lineSeries1.Points.Add(new DataPoint(230, 170.552868003446)); + lineSeries1.Points.Add(new DataPoint(232.5, 172.399869402056)); + lineSeries1.Points.Add(new DataPoint(235, 174.346163347851)); + lineSeries1.Points.Add(new DataPoint(237.5, 176.33268720905)); + lineSeries1.Points.Add(new DataPoint(240, 178.153302327545)); + lineSeries1.Points.Add(new DataPoint(242.5, 180.100497714128)); + lineSeries1.Points.Add(new DataPoint(245, 181.831839179449)); + lineSeries1.Points.Add(new DataPoint(247.5, 183.611763662664)); + lineSeries1.Title = "Average"; + plotModel1.Series.Add(lineSeries1); + return plotModel1; + } + + private static AreaSeries CreateExampleAreaSeries() + { + var areaSeries1 = new AreaSeries(); + areaSeries1.Points.Add(new DataPoint(0, 50)); + areaSeries1.Points.Add(new DataPoint(10, 40)); + areaSeries1.Points.Add(new DataPoint(20, 60)); + areaSeries1.Points2.Add(new DataPoint(0, 60)); + areaSeries1.Points2.Add(new DataPoint(5, 80)); + areaSeries1.Points2.Add(new DataPoint(20, 70)); + return areaSeries1; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/BarSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/BarSeriesExamples.cs new file mode 100644 index 0000000..96df4e7 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/BarSeriesExamples.cs @@ -0,0 +1,1176 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("BarSeries"), Tags("Series")] + public class BarSeriesExamples + { + [Example("With labels")] + public static PlotModel WithLabels() + { + var model = new PlotModel + { + Title = "With labels", + }; + + var rnd = new Random(1); + var series = new List + { + new BarSeries { LabelFormatString = "{0}", LabelPlacement = LabelPlacement.Base, Title = "Base" }, + new BarSeries { LabelFormatString = "{0}", LabelPlacement = LabelPlacement.Inside, Title = "Inside" }, + new BarSeries { LabelFormatString = "{0}", LabelPlacement = LabelPlacement.Middle, Title = "Middle" }, + new BarSeries { LabelFormatString = "{0}", LabelPlacement = LabelPlacement.Outside, Title = "Outside" }, + }; + + for (int i = 0; i < 4; i++) + { + foreach (var s in series) + { + s.Items.Add(new BarItem() { Value = rnd.Next(-100, 100) }); + } + } + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0.06, MaximumPadding = 0.06, ExtraGridlines = new[] { 0d } }; + + foreach (var s in series) + { + model.Series.Add(s); + } + + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + [Example("With labels (at an angle)")] + public static PlotModel WithLabelsAtAnAngle() + { + var model = WithLabels(); + + foreach (BarSeries b in model.Series) + { + b.LabelAngle = -45; + } + + return model; + } + + [Example("With labels (Value Axis reversed)")] + public static PlotModel WithLabelsXAxisReversed() + { + return WithLabels().ReverseXAxis(); + } + + [Example("Stacked")] + [DocumentationExample("Series/BarSeries")] + public static PlotModel StackedSeries() + { + return CreateSimpleModel(true, "Simple stacked model"); + } + + [Example("Multiple Value Axes")] + public static PlotModel MultipleValueAxes() + { + var model = new PlotModel { Title = "Multiple Value Axes" }; + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + var valueAxis1 = new LinearAxis { Title = "Value Axis 1", Position = AxisPosition.Bottom, MinimumPadding = 0.06, MaximumPadding = 0.06, ExtraGridlines = new[] { 0d }, EndPosition = .5, Key = "x1" }; + var valueAxis2 = new LinearAxis { Title = "Value Axis 2", Position = AxisPosition.Bottom, MinimumPadding = 0.06, MaximumPadding = 0.06, ExtraGridlines = new[] { 0d }, StartPosition = .5, Key = "x2" }; + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis1); + model.Axes.Add(valueAxis2); + + var series = new List + { + new BarSeries { XAxisKey = "x1" }, + new BarSeries { XAxisKey = "x1" }, + new BarSeries { XAxisKey = "x2" }, + new BarSeries { XAxisKey = "x2" }, + }; + + var rnd = new Random(1); + foreach (var s in series) + { + for (var i = 0; i < 4; i++) + { + s.Items.Add(new BarItem() { Value = rnd.Next(-100, 100) }); + } + + model.Series.Add(s); + } + + return model; + } + + [Example("Stacked, Multiple Value Axes")] + public static PlotModel StackedMultipleValueAxes() + { + var model = MultipleValueAxes(); + model.Title = $"Stacked, {model.Title}"; + foreach (BarSeries barSeries in model.Series) + { + barSeries.IsStacked = true; + } + + return model; + } + + [Example("Multiple Category Axes")] + public static PlotModel MultipleCategoryAxes() + { + var model = new PlotModel { Title = "Multiple Category Axes" }; + model.Legends.Add(new Legend() { IsLegendVisible = true, LegendPosition = LegendPosition.TopLeft, LegendPlacement = LegendPlacement.Inside }); + + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, Key = "x", ExtraGridlines = new[] { 0d } }; + var categoryAxis1 = new CategoryAxis { Title = "Category Axis 1", Position = AxisPosition.Left, MinimumPadding = 0.06, MaximumPadding = 0.06, EndPosition = .5, Key = "y1" }; + var categoryAxis2 = new CategoryAxis { Title = "Category Axis 2", Position = AxisPosition.Left, MinimumPadding = 0.06, MaximumPadding = 0.06, StartPosition = .5, Key = "y2" }; + model.Axes.Add(valueAxis); + model.Axes.Add(categoryAxis1); + model.Axes.Add(categoryAxis2); + + var series = new List + { + new BarSeries { YAxisKey = "y1", XAxisKey = "x", RenderInLegend = true, Title = "Y1A" }, + new BarSeries { YAxisKey = "y1", XAxisKey = "x", RenderInLegend = true, Title = "Y1B" }, + new BarSeries { YAxisKey = "y2", XAxisKey = "x", RenderInLegend = true, Title = "Y2A" }, + new BarSeries { YAxisKey = "y2", XAxisKey = "x", RenderInLegend = true, Title = "Y2B" }, + }; + + var rnd = new Random(1); + foreach (var s in series) + { + for (var i = 0; i < 4; i++) + { + s.Items.Add(new BarItem() { Value = rnd.Next(-100, 100) }); + } + + model.Series.Add(s); + } + + return model; + } + + [Example("Stacked, Multiple Category Axes")] + public static PlotModel StackedMultipleCategoryAxes() + { + var model = MultipleCategoryAxes(); + model.Title = $"Stacked, {model.Title}"; + foreach (BarSeries barSeries in model.Series) + { + barSeries.IsStacked = true; + } + + return model; + } + + [Example("Empty series")] + public static PlotModel EmptySeries() + { + var model = new PlotModel { Title = "Empty series" }; + + var s1 = new BarSeries { Title = "Series 1" }; + var s2 = new BarSeries { Title = "Series 2" }; + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0 }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + [Example("No category axis defined")] + public static PlotModel NoCategoryAxisDefined() + { + var model = new PlotModel { Title = "No category axis defined" }; + + var s1 = new BarSeries { Title = "Series 1", ItemsSource = new[] { new BarItem { Value = 25 }, new BarItem { Value = 137 } } }; + var s2 = new BarSeries { Title = "Series 2", ItemsSource = new[] { new BarItem { Value = 52 }, new BarItem { Value = 317 } } }; + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0 }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(valueAxis); + return model; + } + + [Example("Binding to ItemsSource")] + public static PlotModel BindingItemsSource() + { + var items = new Collection + { + new Item { Label = "Apples", Value1 = 37, Value2 = 12, Value3 = 19 }, + new Item { Label = "Pears", Value1 = 7, Value2 = 21, Value3 = 9 }, + new Item { Label = "Bananas", Value1 = 23, Value2 = 2, Value3 = 29 } + }; + + var plotModel1 = new PlotModel { Title = "Binding to ItemsSource" }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + plotModel1.Legends.Add(l); + + var categoryAxis1 = new CategoryAxis { Position = AxisPosition.Left, LabelField = "Label", ItemsSource = items, MajorStep = 1, MinorStep = 1 }; + plotModel1.Axes.Add(categoryAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Bottom, AbsoluteMinimum = 0, MinimumPadding = 0 }; + plotModel1.Axes.Add(linearAxis1); + var series1 = new BarSeries + { + FillColor = OxyColor.FromArgb(255, 78, 154, 6), + ValueField = "Value1", + Title = "2009", + ItemsSource = items + }; + plotModel1.Series.Add(series1); + var series2 = new BarSeries + { + FillColor = OxyColor.FromArgb(255, 200, 141, 0), + ValueField = "Value2", + Title = "2010", + ItemsSource = items + }; + plotModel1.Series.Add(series2); + var series3 = new BarSeries + { + FillColor = OxyColor.FromArgb(255, 204, 0, 0), + ValueField = "Value3", + Title = "2011", + ItemsSource = items + }; + plotModel1.Series.Add(series3); + return plotModel1; + } + + [Example("Binding to ItemsSource (array)")] + public static PlotModel BindingToItemsSourceArray() + { + var model = new PlotModel { Title = "Binding to ItemsSource", Subtitle = "The items are defined by an array of BarItem/ColumnItem" }; + model.Series.Add(new BarSeries { Title = "Series 1", ItemsSource = new[] { new BarItem { Value = 25 }, new BarItem { Value = 137 } } }); + model.Series.Add(new BarSeries { Title = "Series 2", ItemsSource = new[] { new BarItem { Value = 52 }, new BarItem { Value = 317 } } }); + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0 }); + return model; + } + + [Example("Binding to ItemsSource (list)")] + public static PlotModel BindingToItemsSourceListT() + { + var model = new PlotModel { Title = "Binding to ItemsSource", Subtitle = "The items are defined by a List of BarItem/ColumnItem" }; + model.Series.Add(new BarSeries { Title = "Series 1", ItemsSource = new List(new[] { new BarItem { Value = 25 }, new BarItem { Value = 137 } }) }); + model.Series.Add(new BarSeries { Title = "Series 2", ItemsSource = new List(new[] { new BarItem { Value = 52 }, new BarItem { Value = 317 } }) }); + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0 }); + return model; + } + + [Example("Binding to ItemsSource (reflection)")] + public static PlotModel BindingToItemsSourceReflection() + { + var model = new PlotModel { Title = "Binding to ItemsSource", Subtitle = "Reflect by 'ValueField'" }; + model.Series.Add(new BarSeries { Title = "Series 1", ValueField = "Value1", ItemsSource = new[] { new Item { Value1 = 25 }, new Item { Value1 = 137 } } }); + model.Series.Add(new BarSeries { Title = "Series 2", ValueField = "Value1", ItemsSource = new[] { new Item { Value1 = 52 }, new Item { Value1 = 317 } } }); + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0 }); + return model; + } + + [Example("Defined by Items")] + public static PlotModel DefinedByItems() + { + var model = new PlotModel { Title = "Defined by Items", Subtitle = "The items are added to the `Items` property." }; + + var s1 = new BarSeries { Title = "Series 1" }; + s1.Items.AddRange(new[] { new BarItem { Value = 25 }, new BarItem { Value = 137 } }); + var s2 = new BarSeries { Title = "Series 2" }; + s2.Items.AddRange(new[] { new BarItem { Value = 52 }, new BarItem { Value = 317 } }); + model.Series.Add(s1); + model.Series.Add(s2); + + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0 }); + return model; + } + + [Example("Empty category axis")] + public static PlotModel EmptyCategoryAxis() + { + var model = new PlotModel { Title = "Empty category axis" }; + + var s1 = new BarSeries { Title = "Series 1" }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 137 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + var s2 = new BarSeries { Title = "Series 2" }; + s2.Items.Add(new BarItem { Value = -12 }); + s2.Items.Add(new BarItem { Value = -14 }); + s2.Items.Add(new BarItem { Value = -120 }); + s2.Items.Add(new BarItem { Value = -26 }); + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + var valueAxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0.06, + MaximumPadding = 0.06, + ExtraGridlines = new[] { 0.0 }, + ExtraGridlineStyle = LineStyle.Solid, + ExtraGridlineColor = OxyColors.Black, + ExtraGridlineThickness = 1 + }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + [Example("With negative values")] + public static PlotModel WithNegativeValue() + { + return CreateModelWithNegativeValues(false, "With negative values"); + } + + [Example("Stacked with negative values")] + public static PlotModel StackedWithNegativeValue() + { + return CreateModelWithNegativeValues(true, "Stacked with negative values"); + } + + [Example("Mixed with LineSeries")] + public static PlotModel MixedWithLineSeries() + { + var model = CreateSimpleModel(false, "Mixed with LineSeries"); + model.Title = "Mixed with LineSeries"; + var s1 = new LineSeries { Title = "LineSeries 1" }; + s1.Points.Add(new DataPoint(25, 0)); + s1.Points.Add(new DataPoint(137, 1)); + s1.Points.Add(new DataPoint(18, 2)); + s1.Points.Add(new DataPoint(40, 3)); + + model.Series.Add(s1); + return model; + } + + [Example("No axes defined")] + public static PlotModel NoAxes() + { + var model = CreateSimpleModel(false, "No axes defined"); + model.Axes.Clear(); // default axes will be generated + return model; + } + + [Example("Stacked and no axes defined")] + public static PlotModel StackedNoAxes() + { + var model = CreateSimpleModel(true, "Stacked and no axes defined"); + model.Axes.Clear(); // default axes will be generated + return model; + } + + [Example("Logarithmic axis (Base Value)")] + public static PlotModel LogAxisBaseValue() + { + var model = new PlotModel + { + Title = "Logarithmic axis" + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + var s1 = new BarSeries { Title = "Series 1", BaseValue = 0.1, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 37 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + model.Series.Add(s1); + model.Axes.Add(categoryAxis); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom, Minimum = 0.1, MinimumPadding = 0, AbsoluteMinimum = 0 }); + return model; + } + + [Example("Logarithmic axis (Base Line)")] + public static PlotModel LogAxisBaseLine() + { + var model = new PlotModel + { + Title = "Logarithmic axis" + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + var s1 = new BarSeries { Title = "Series 1", BaseLine = 0.1, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 37 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + model.Series.Add(s1); + model.Axes.Add(categoryAxis); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom, MinimumPadding = 0, AbsoluteMinimum = 0 }); + return model; + } + + [Example("Logarithmic axis (not stacked)")] + public static PlotModel LogAxisNotStacked() + { + var model = new PlotModel { Title = "Logarithmic axis" }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + var items = new Collection + { + new Item {Label = "Apples", Value1 = 37, Value2 = 12, Value3 = 19}, + new Item {Label = "Pears", Value1 = 7, Value2 = 21, Value3 = 9}, + new Item {Label = "Bananas", Value1 = 23, Value2 = 2, Value3 = 29} + }; + + model.Series.Add(new BarSeries { Title = "2009", ItemsSource = items, ValueField = "Value1" }); + model.Series.Add(new BarSeries { Title = "2010", ItemsSource = items, ValueField = "Value2" }); + model.Series.Add(new BarSeries { Title = "2011", ItemsSource = items, ValueField = "Value3" }); + + model.Axes.Add(new CategoryAxis { Position = AxisPosition.Left, ItemsSource = items, LabelField = "Label" }); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom, Minimum = 1 }); + return model; + } + + [Example("Logarithmic axis (stacked series)")] + public static PlotModel LogAxisStacked() + { + var model = LogAxisNotStacked(); + foreach (var s in model.Series.OfType()) + { + s.IsStacked = true; + } + + return model; + } + + private static PlotModel CreateSimpleModel(bool stacked, string title) + { + var model = new PlotModel + { + Title = title + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + + var s1 = new BarSeries { Title = "Series 1", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 137 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + + var s2 = new BarSeries { Title = "Series 2", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s2.Items.Add(new BarItem { Value = 12 }); + s2.Items.Add(new BarItem { Value = 14 }); + s2.Items.Add(new BarItem { Value = 120 }); + s2.Items.Add(new BarItem { Value = 26 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0 }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + private static PlotModel CreateModelWithNegativeValues(bool stacked, string title) + { + var model = new PlotModel + { + Title = title + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + + var s1 = new BarSeries { Title = "Series 1", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 137 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + + var s2 = new BarSeries { Title = "Series 2", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s2.Items.Add(new BarItem { Value = -12 }); + s2.Items.Add(new BarItem { Value = -14 }); + s2.Items.Add(new BarItem { Value = -120 }); + s2.Items.Add(new BarItem { Value = -26 }); + + var s3 = new BarSeries { Title = "Series 3", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s3.Items.Add(new BarItem { Value = 21 }); + s3.Items.Add(new BarItem { Value = 8 }); + s3.Items.Add(new BarItem { Value = 48 }); + s3.Items.Add(new BarItem { Value = 3 }); + + var s4 = new BarSeries { Title = "Series 4", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s4.Items.Add(new BarItem { Value = -8 }); + s4.Items.Add(new BarItem { Value = -21 }); + s4.Items.Add(new BarItem { Value = -3 }); + s4.Items.Add(new BarItem { Value = -48 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + + var valueAxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0.06, + MaximumPadding = 0.06, + ExtraGridlines = new[] { 0.0 }, + ExtraGridlineStyle = LineStyle.Solid, + ExtraGridlineColor = OxyColors.Black, + ExtraGridlineThickness = 1 + }; + + model.Series.Add(s1); + model.Series.Add(s2); + model.Series.Add(s3); + model.Series.Add(s4); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + public class Item + { + public string Label { get; set; } + public double Value1 { get; set; } + public double Value2 { get; set; } + public double Value3 { get; set; } + } + + public class HistogramBin + { + public string Label { get; set; } + public double Value { get; set; } + } + + [Example("Histogram (bins=5)")] + public static PlotModel Histogram3() + { + return CreateHistogram(100000, 5); + } + + [Example("Histogram (bins=20)")] + public static PlotModel Histogram20() + { + return CreateHistogram(100000, 20); + } + + [Example("Histogram (bins=200)")] + public static PlotModel Histogram200() + { + return CreateHistogram(100000, 200); + } + + public static PlotModel CreateHistogram(int n, int binCount) + { + var bins = new HistogramBin[binCount]; + for (int i = 0; i < bins.Length; i++) + { + bins[i] = new HistogramBin { Label = i.ToString() }; + } + + var r = new Random(31); + for (int i = 0; i < n; i++) + { + int value = r.Next(binCount); + bins[value].Value++; + } + + var temp = new PlotModel { Title = string.Format("Histogram (bins={0}, n={1})", binCount, n), Subtitle = "Pseudorandom numbers" }; + var series1 = new BarSeries { ItemsSource = bins, ValueField = "Value" }; + if (binCount < 100) + { + series1.LabelFormatString = "{0}"; + } + + temp.Series.Add(series1); + + temp.Axes.Add(new CategoryAxis { Position = AxisPosition.Left, ItemsSource = bins, LabelField = "Label", GapWidth = 0 }); + temp.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0, MaximumPadding = 0.1, AbsoluteMinimum = 0 }); + + return temp; + } + + [Example("Histogram (standard normal distribution)")] + public static PlotModel HistogramStandardNormalDistribution() + { + return CreateNormalDistributionHistogram(100000, 2000); + } + + public static PlotModel CreateNormalDistributionHistogram(int n, int binCount) + { + var bins = new HistogramBin[binCount]; + double min = -10; + double max = 10; + for (int i = 0; i < bins.Length; i++) + { + var v = min + (max - min) * i / (bins.Length - 1); + bins[i] = new HistogramBin { Label = v.ToString("0.0") }; + } + + var r = new Random(31); + for (int i = 0; i < n; i++) + { + // http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + var u1 = r.NextDouble(); + var u2 = r.NextDouble(); + var v = Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2); + + int bin = (int)Math.Round((v - min) / (max - min) * (bins.Length - 1)); + if (bin >= 0 && bin < bins.Length) + { + bins[bin].Value++; + } + } + + var temp = new PlotModel { Title = string.Format("Histogram (bins={0}, n={1})", binCount, n), Subtitle = "Standard normal distribution by Box-Muller transform" }; + var series1 = new BarSeries { ItemsSource = bins, ValueField = "Value" }; + temp.Series.Add(series1); + + var categoryAxis = new CategoryAxis + { + Position = AxisPosition.Left, + GapWidth = 0 + }; + + categoryAxis.Labels.AddRange(bins.Select(b => b.Label)); + categoryAxis.IsAxisVisible = false; + temp.Axes.Add(categoryAxis); + + // todo: link category and linear axis + temp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = min, Maximum = max }); + + temp.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0, AbsoluteMinimum = 0 }); + + return temp; + } + + [Example("Different colors within the same series")] + public static PlotModel DifferentColors() + { + var model = new PlotModel { Title = "Different colors within the same series" }; + var series = new BarSeries { Title = "Series 1" }; + series.Items.Add(new BarItem { Value = 1, Color = OxyColors.Red }); + series.Items.Add(new BarItem { Value = 2, Color = OxyColors.Green }); + series.Items.Add(new BarItem { Value = 1, Color = OxyColors.Blue }); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B", "C" }); + model.Axes.Add(categoryAxis); + + model.Series.Add(series); + return model; + } + + [Example("Different stacking groups")] + public static PlotModel StackingGroups() + { + var model = new PlotModel { Title = "Stacking groups" }; + var series = new BarSeries { Title = "Series 1", StackGroup = "1", IsStacked = true }; + series.Items.Add(new BarItem { Value = 1 }); + series.Items.Add(new BarItem { Value = 2 }); + model.Series.Add(series); + + var series2 = new BarSeries { Title = "Series 2", StackGroup = "2", IsStacked = true }; + series2.Items.Add(new BarItem { Value = 2 }); + series2.Items.Add(new BarItem { Value = 1 }); + model.Series.Add(series2); + + var series3 = new BarSeries { Title = "Series 3", StackGroup = "1", IsStacked = true }; + series3.Items.Add(new BarItem { Value = 3 }); + series3.Items.Add(new BarItem { Value = 1 }); + model.Series.Add(series3); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + return model; + } + + [Example("Different widths")] + public static PlotModel DifferentWidths() + { + var model = new PlotModel { Title = "Different widths", Subtitle = "Series1=0.6 and Series2=0.3" }; + var series1 = new BarSeries { Title = "Series 1", BarWidth = 0.6 }; + series1.Items.Add(new BarItem { Value = 1 }); + series1.Items.Add(new BarItem { Value = 2 }); + model.Series.Add(series1); + + var series2 = new BarSeries { Title = "Series 2", BarWidth = 0.3 }; + series2.Items.Add(new BarItem { Value = 3 }); + series2.Items.Add(new BarItem { Value = 1 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("Different widths (stacked)")] + public static PlotModel DifferentWidthsStacked() + { + var model = new PlotModel { Title = "Different widths (stacked)" }; + var series1 = new BarSeries { Title = "Series 1", IsStacked = true, BarWidth = 0.6 }; + series1.Items.Add(new BarItem { Value = 1 }); + series1.Items.Add(new BarItem { Value = 2 }); + model.Series.Add(series1); + + var series2 = new BarSeries { Title = "Series 2", IsStacked = true, BarWidth = 0.3 }; + series2.Items.Add(new BarItem { Value = 3 }); + series2.Items.Add(new BarItem { Value = 1 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("Invalid values")] + public static PlotModel InvalidValues() + { + var model = new PlotModel { Title = "Invalid values", Subtitle = "Series 1 contains a NaN value for category B." }; + var series1 = new BarSeries { Title = "Series 1" }; + series1.Items.Add(new BarItem { Value = 1 }); + series1.Items.Add(new BarItem { Value = double.NaN }); + model.Series.Add(series1); + + var series2 = new BarSeries { Title = "Series 2" }; + series2.Items.Add(new BarItem { Value = 3 }); + series2.Items.Add(new BarItem { Value = 1 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("Missing values")] + public static PlotModel MissingValues() + { + var model = new PlotModel { Title = "Missing values", Subtitle = "Series 1 contains only one item with CategoryIndex = 1" }; + var series1 = new BarSeries { Title = "Series 1" }; + series1.Items.Add(new BarItem { Value = 1, CategoryIndex = 1 }); + model.Series.Add(series1); + + var series2 = new BarSeries { Title = "Series 2" }; + series2.Items.Add(new BarItem { Value = 3 }); + series2.Items.Add(new BarItem { Value = 1.2 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("CategoryIndex")] + public static PlotModel CategoryIndex() + { + var model = new PlotModel { Title = "CategoryIndex", Subtitle = "Setting CategoryIndex = 0 for both items in the series." }; + var series = new BarSeries { Title = "Series 1", StrokeThickness = 1 }; + series.Items.Add(new BarItem { Value = 1, CategoryIndex = 0 }); + series.Items.Add(new BarItem { Value = 2, CategoryIndex = 0 }); + model.Series.Add(series); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("CategoryIndex (stacked)")] + public static PlotModel CategoryIndexStacked() + { + var model = new PlotModel { Title = "CategoryIndex (stacked)", Subtitle = "Setting CategoryIndex = 0 for both items in the series." }; + var series = new BarSeries { Title = "Series 1", IsStacked = true, StrokeThickness = 1 }; + series.Items.Add(new BarItem { Value = 1, CategoryIndex = 0 }); + series.Items.Add(new BarItem { Value = 2, CategoryIndex = 0 }); + model.Series.Add(series); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("BaseValue")] + public static PlotModel BaseValue() + { + var model = new PlotModel { Title = "BaseValue", Subtitle = "BaseValue = -1" }; + var series1 = new BarSeries { Title = "Series 1", BaseValue = -1 }; + series1.Items.Add(new BarItem { Value = 1 }); + series1.Items.Add(new BarItem { Value = 2 }); + model.Series.Add(series1); + var series2 = new BarSeries { Title = "Series 2", BaseValue = -1 }; + series2.Items.Add(new BarItem { Value = 4 }); + series2.Items.Add(new BarItem { Value = 7 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + + return model; + } + + [Example("BaseValue (stacked)")] + public static PlotModel BaseValueStacked() + { + var model = new PlotModel { Title = "BaseValue (stacked)", Subtitle = "BaseValue = -1" }; + var series1 = new BarSeries { Title = "Series 1", IsStacked = true, BaseValue = -1 }; + series1.Items.Add(new BarItem { Value = 1 }); + series1.Items.Add(new BarItem { Value = 2 }); + model.Series.Add(series1); + var series2 = new BarSeries { Title = "Series 2", IsStacked = true, BaseValue = -1 }; + series2.Items.Add(new BarItem { Value = 4 }); + series2.Items.Add(new BarItem { Value = 7 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + return model; + } + + [Example("BaseValue (overlaping)")] + public static PlotModel BaseValueOverlaping() + { + var model = new PlotModel { Title = "BaseValue (overlaping)", Subtitle = "BaseValue = -1" }; + var series1 = new BarSeries { Title = "Series 1", IsStacked = true, OverlapsStack = true, BaseValue = -1 }; + series1.Items.Add(new BarItem { Value = 1 }); + series1.Items.Add(new BarItem { Value = 2 }); + model.Series.Add(series1); + var series2 = new BarSeries { Title = "Series 2", IsStacked = true, OverlapsStack = true, BaseValue = -1, BarWidth = 0.5 }; + series2.Items.Add(new BarItem { Value = 4 }); + series2.Items.Add(new BarItem { Value = 7 }); + model.Series.Add(series2); + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left + }; + categoryAxis.Labels.AddRange(new[] { "A", "B" }); + model.Axes.Add(categoryAxis); + return model; + } + + [Example("BaseValue (labels)")] + public static PlotModel BaseValueLabels() + { + var model = new PlotModel { Title = "BaseValue with Labels" }; + + foreach (var placement in new[] { LabelPlacement.Base, LabelPlacement.Inside, LabelPlacement.Middle, LabelPlacement.Outside }) + { + var bs = new BarSeries { Title = placement.ToString(), BaseValue = -25, LabelPlacement = placement, LabelFormatString = "{0:0}" }; + bs.Items.Add(new BarItem { Value = -40 }); + bs.Items.Add(new BarItem { Value = -25 }); + bs.Items.Add(new BarItem { Value = -10 }); + bs.Items.Add(new BarItem { Value = 0 }); + bs.Items.Add(new BarItem { Value = 10 }); + model.Series.Add(bs); + } + + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left, + StartPosition = 1, + EndPosition = 0, + }; + categoryAxis.Labels.AddRange(new[] { "A", "B", "C", "D", "E" }); + model.Axes.Add(categoryAxis); + + model.Legends.Add(new Legend()); + + return model; + } + + [Example("Stacked (labels)")] + public static PlotModel StackedLabels() + { + var model = new PlotModel { Title = "Stacked with Labels" }; + + int i = 0; + foreach (var placement in new[] { LabelPlacement.Base, LabelPlacement.Inside, LabelPlacement.Middle, LabelPlacement.Outside }) + { + var categoryAxis = new CategoryAxis + { + Title = "Category", + Position = AxisPosition.Left, + StartPosition = 1 - i * 0.25, + EndPosition = 0.75 - i * 0.25, + Key = $"C{i}", + }; + + var bs1 = new BarSeries { Title = placement.ToString(), LabelPlacement = placement, LabelFormatString = "{0:0}", IsStacked = true, YAxisKey = categoryAxis.Key }; + bs1.Items.Add(new BarItem { Value = 5 }); + bs1.Items.Add(new BarItem { Value = 10 }); + bs1.Items.Add(new BarItem { Value = 15 }); + model.Series.Add(bs1); + + var bs2 = new BarSeries { Title = placement.ToString(), LabelPlacement = placement, LabelFormatString = "{0:0}", IsStacked = true, YAxisKey = categoryAxis.Key }; + bs2.Items.Add(new BarItem { Value = 15 }); + bs2.Items.Add(new BarItem { Value = 10 }); + bs2.Items.Add(new BarItem { Value = 5 }); + model.Series.Add(bs2); + + categoryAxis.Labels.AddRange(new[] { "A", "B", "C" }); + model.Axes.Add(categoryAxis); + + i++; + } + + model.Legends.Add(new Legend()); + + return model; + } + + [Example("GapWidth 0%")] + public static PlotModel GapWidth0() + { + return CreateGapWidthModel(0, "GapWidth 0%"); + } + + [Example("GapWidth 100% (default)")] + public static PlotModel GapWidth100() + { + return CreateGapWidthModel(1, "GapWidth 100% (default)"); + } + + [Example("GapWidth 200%")] + public static PlotModel GapWidth200() + { + return CreateGapWidthModel(2, "GapWidth 200%"); + } + + private static PlotModel CreateGapWidthModel(double gapWidth, string title) + { + var model = CreateSimpleModel(false, title); + ((CategoryAxis)model.Axes[0]).GapWidth = gapWidth; + return model; + } + + [Example("All in one")] + public static PlotModel AllInOne() + { + var model = new PlotModel + { + Title = "All in one" + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left, GapWidth = 0.01 }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + var valueAxis = new LinearAxis + { + Position = AxisPosition.Bottom, + MinimumPadding = 0.06, + MaximumPadding = 0.06, + ExtraGridlines = new[] { 0.0 }, + ExtraGridlineStyle = LineStyle.Solid, + ExtraGridlineColor = OxyColors.Black, + ExtraGridlineThickness = 1 + }; + + var categoryA = 0; + var categoryB = 1; + var categoryC = 2; + var categoryD = 3; + + var s1 = new BarSeries { Title = "Series 1", IsStacked = true, StrokeColor = OxyColors.Black, StrokeThickness = 1, StackGroup = "3" }; + s1.Items.Add(new BarItem { Value = 25 }); + s1.Items.Add(new BarItem { Value = 137 }); + s1.Items.Add(new BarItem { Value = 18 }); + s1.Items.Add(new BarItem { Value = 40 }); + var s2 = new BarSeries { Title = "Series 2", IsStacked = true, StrokeColor = OxyColors.Black, StrokeThickness = 1, StackGroup = "3" }; + s2.Items.Add(new BarItem { Value = -12 }); + s2.Items.Add(new BarItem { Value = -14 }); + s2.Items.Add(new BarItem { Value = -120 }); + s2.Items.Add(new BarItem { Value = -26 }); + + var s3 = new BarSeries { Title = "Series 3", IsStacked = true, StrokeColor = OxyColors.Black, StrokeThickness = 1, StackGroup = "5", IsVisible = false }; + s3.Items.Add(new BarItem { Value = 21 }); + s3.Items.Add(new BarItem { Value = 8 }); + s3.Items.Add(new BarItem { Value = 48 }); + s3.Items.Add(new BarItem { Value = 3 }); + var s4 = new BarSeries { Title = "Series 4", IsStacked = true, StrokeColor = OxyColors.Black, StrokeThickness = 1, StackGroup = "5", LabelFormatString = "{0:0}", LabelPlacement = LabelPlacement.Middle }; + s4.Items.Add(new BarItem { Value = -8, CategoryIndex = categoryA }); + s4.Items.Add(new BarItem { Value = -8, CategoryIndex = categoryA }); + s4.Items.Add(new BarItem { Value = -8, CategoryIndex = categoryA }); + s4.Items.Add(new BarItem { Value = -21, CategoryIndex = categoryB }); + s4.Items.Add(new BarItem { Value = -3, CategoryIndex = categoryC }); + s4.Items.Add(new BarItem { Value = -48, CategoryIndex = categoryD }); + s4.Items.Add(new BarItem { Value = 8, CategoryIndex = categoryA }); + s4.Items.Add(new BarItem { Value = 21, CategoryIndex = categoryB }); + s4.Items.Add(new BarItem { Value = 3, CategoryIndex = categoryC }); + s4.Items.Add(new BarItem { Value = 48, CategoryIndex = categoryD }); + + var s5 = new BarSeries { Title = "Series 5", IsStacked = false, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s5.Items.Add(new BarItem { Value = 17, CategoryIndex = categoryA }); + s5.Items.Add(new BarItem { Value = 179, CategoryIndex = categoryB }); + s5.Items.Add(new BarItem { Value = 45, CategoryIndex = categoryC }); + s5.Items.Add(new BarItem { Value = 65, CategoryIndex = categoryD }); + s5.Items.Add(new BarItem { Value = 97, CategoryIndex = categoryA }); + s5.Items.Add(new BarItem { Value = 21, CategoryIndex = categoryD }); + + var s6 = new BarSeries { Title = "Series 6", IsStacked = false, StrokeColor = OxyColors.Black, StrokeThickness = 1, LabelFormatString = "{0:0}", LabelPlacement = LabelPlacement.Base }; + s6.Items.Add(new BarItem { Value = 7 }); + s6.Items.Add(new BarItem { Value = 54 }); + s6.Items.Add(new BarItem { Value = 68 }); + s6.Items.Add(new BarItem { Value = 12 }); + + var s7 = new BarSeries { Title = "Series 7", IsStacked = true, OverlapsStack = true, StrokeColor = OxyColors.Black, StrokeThickness = 1, LabelFormatString = "{0:0}", LabelPlacement = LabelPlacement.Base, StackGroup = "3", BarWidth = 0.5 }; + s7.Items.Add(new BarItem { Value = 10 }); + s7.Items.Add(new BarItem { Value = 80 }); + s7.Items.Add(new BarItem { Value = 100, CategoryIndex = categoryD }); + + model.Series.Add(s1); + model.Series.Add(s2); + model.Series.Add(s3); + model.Series.Add(s4); + model.Series.Add(s5); + model.Series.Add(s6); + model.Series.Add(s7); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/BoxPlotSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/BoxPlotSeriesExamples.cs new file mode 100644 index 0000000..c957cf2 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/BoxPlotSeriesExamples.cs @@ -0,0 +1,201 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Gets the median. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("BoxPlotSeries"), Tags("Series")] + public class BoxPlotSeriesExamples + { + [Example("BoxPlot")] + public static PlotModel BoxPlot() + { + const int boxes = 10; + + var model = new PlotModel { Title = string.Format("BoxPlot (n={0})", boxes) }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + + var s1 = new BoxPlotSeries + { + Title = "BoxPlotSeries", + BoxWidth = 0.3 + }; + + var random = new Random(31); + for (var i = 0; i < boxes; i++) + { + double x = i; + var points = 5 + random.Next(15); + var values = new List(); + for (var j = 0; j < points; j++) + { + values.Add(random.Next(0, 20)); + } + + values.Sort(); + var median = GetMedian(values); + var mean = values.Average(); + int r = values.Count % 2; + double firstQuartil = GetMedian(values.Take((values.Count + r) / 2)); + double thirdQuartil = GetMedian(values.Skip((values.Count - r) / 2)); + + var iqr = thirdQuartil - firstQuartil; + var step = iqr * 1.5; + var upperWhisker = thirdQuartil + step; + upperWhisker = values.Where(v => v <= upperWhisker).Max(); + var lowerWhisker = firstQuartil - step; + lowerWhisker = values.Where(v => v >= lowerWhisker).Min(); + + var outliers = new[] { upperWhisker + random.Next(1, 10), lowerWhisker - random.Next(1, 10) }; + + s1.Items.Add(new BoxPlotItem(x, lowerWhisker, firstQuartil, median, thirdQuartil, upperWhisker) { Mean = mean, Outliers = outliers }); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0.1, MaximumPadding = 0.1 }); + return model; + } + + /// + /// Gets the median. + /// + /// The values. + /// + private static double GetMedian(IEnumerable values) + { + var sortedInterval = new List(values); + sortedInterval.Sort(); + var count = sortedInterval.Count; + if (count % 2 == 1) + { + return sortedInterval[(count - 1) / 2]; + } + + return 0.5 * sortedInterval[count / 2] + 0.5 * sortedInterval[(count / 2) - 1]; + } + + [Example("BoxPlot (minimal data/ink ratio)")] + public static PlotModel BoxPlot2() + { + var model = BoxPlot(); + var boxPlotSeries = (BoxPlotSeries)model.Series[0]; + boxPlotSeries.ShowMedianAsDot = true; + boxPlotSeries.OutlierType = MarkerType.Cross; + boxPlotSeries.Fill = OxyColors.Black; + boxPlotSeries.ShowBox = false; + boxPlotSeries.WhiskerWidth = 0; + return model; + } + + [Example("BoxPlot (dashed line)")] + public static PlotModel BoxPlot3() + { + var model = BoxPlot(); + var boxPlotSeries = (BoxPlotSeries)model.Series[0]; + boxPlotSeries.LineStyle = LineStyle.Dash; + return model; + } + + [Example("Outlier type = Cross")] + public static PlotModel OutlierTypeCross() + { + var model = BoxPlot(); + var boxPlotSeries = (BoxPlotSeries)model.Series[0]; + boxPlotSeries.OutlierType = MarkerType.Cross; + return model; + } + + [Example("Outlier type = Custom")] + public static PlotModel OutlierTypeCustom() + { + var model = BoxPlot(); + var boxPlotSeries = (BoxPlotSeries)model.Series[0]; + boxPlotSeries.OutlierType = MarkerType.Custom; + boxPlotSeries.OutlierOutline = new[] { new ScreenPoint(-1, -1), new ScreenPoint(1, 1), new ScreenPoint(-1, 1), new ScreenPoint(1, -1) }; + return model; + } + + [Example("Michelson-Morley experiment")] + public static PlotModel MichelsonMorleyExperiment() + { + //// http://www.gutenberg.org/files/11753/11753-h/11753-h.htm + //// http://en.wikipedia.org/wiki/Michelson%E2%80%93Morley_experiment + //// http://stat.ethz.ch/R-manual/R-devel/library/datasets/html/morley.html + + var model = new PlotModel(); + + var boxPlotSeries = new BoxPlotSeries + { + Title = "Results", + Stroke = OxyColors.Black, + StrokeThickness = 1, + OutlierSize = 2, + BoxWidth = 0.4 + }; + + // note: approximated data values (not the original values) + boxPlotSeries.Items.Add(new BoxPlotItem(0, 740, 850, 945, 980, 1070) { Outliers = new[] { 650.0 }}); + boxPlotSeries.Items.Add(new BoxPlotItem(1, 750, 805, 845, 890, 970) { Outliers = new double[] { }}); + boxPlotSeries.Items.Add(new BoxPlotItem(2, 845, 847, 855, 880, 910) { Outliers = new[] { 640.0, 950, 970 }}); + boxPlotSeries.Items.Add(new BoxPlotItem(3, 720, 760, 820, 870, 910) { Outliers = new double[] { }}); + boxPlotSeries.Items.Add(new BoxPlotItem(4, 730, 805, 807, 870, 950) { Outliers = new double[] { }}); + model.Series.Add(boxPlotSeries); + model.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Horizontal, LineStyle = LineStyle.Solid, Y = 792.458, Text = "true speed" }); + var categoryAxis = new CategoryAxis + { + Title = "Experiment No.", + }; + categoryAxis.Labels.AddRange(new[] { "1", "2", "3", "4", "5" }); + model.Axes.Add(categoryAxis); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Speed of light (km/s minus 299,000)", MajorStep = 100, MinorStep = 100 }); + return model; + } + + [Example("BoxPlot (DateTime axis)")] + [DocumentationExample("Series/BoxPlotSeries")] + public static PlotModel BoxPlotSeries_DateTimeAxis() + { + var m = new PlotModel(); + var x0 = DateTimeAxis.ToDouble(new DateTime(2013, 05, 04)); + m.Axes.Add(new DateTimeAxis + { + Position = AxisPosition.Bottom, + Minimum = x0 - 0.9, + Maximum = x0 + 1.9, + IntervalType = DateTimeIntervalType.Days, + MajorStep = 1, + MinorStep = 1, + StringFormat = "yyyy-MM-dd" + }); + var boxPlotSeries = new BoxPlotSeries + { + TrackerFormatString = "X: {1:yyyy-MM-dd}\nUpper Whisker: {2:0.00}\nThird Quartil: {3:0.00}\nMedian: {4:0.00}\nFirst Quartil: {5:0.00}\nLower Whisker: {6:0.00}\nMean: {7:0.00}" + }; + boxPlotSeries.Items.Add(new BoxPlotItem(x0, 10, 14, 16, 20, 22) { Mean = 17, Outliers = new[] { 23.5 }}); + boxPlotSeries.Items.Add(new BoxPlotItem(x0 + 1, 11, 13, 14, 15, 18) { Outliers = new[] { 23.4 }}); + m.Series.Add(boxPlotSeries); + return m; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/ContourSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/ContourSeriesExamples.cs new file mode 100644 index 0000000..767f5f9 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/ContourSeriesExamples.cs @@ -0,0 +1,216 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Linq; + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("ContourSeries"), Tags("Series")] + public class ContourSeriesExamples + { + private static Func peaks = (x, y) => + 3 * (1 - x) * (1 - x) * Math.Exp(-(x * x) - (y + 1) * (y + 1)) + - 10 * (x / 5 - x * x * x - y * y * y * y * y) * Math.Exp(-x * x - y * y) + - 1.0 / 3 * Math.Exp(-(x + 1) * (x + 1) - y * y); + + private static Func openContours = (x, y) => + (x * x) / (y * y + 1) + + (y * y) / (x * x + 1); + + [Example("Peaks")] + public static PlotModel Peaks() + { + var model = new PlotModel { Title = "Peaks" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05) + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks LabelStep = 1, ContourLevelStep = PI/2")] + public static PlotModel PeaksLabelStep1LevelStepPI2() + { + var model = new PlotModel { Title = "Peaks LabelStep = 1, ContourLevelStep = PI/2" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + ContourLevelStep = Math.PI / 2, + LabelStep = 1 + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks LabelStep = 2, ContourLevelStep = 0.5")] + public static PlotModel PeaksLabelStep2() + { + var model = new PlotModel { Title = "Peaks LabelStep = 2, ContourLevelStep = 0.5" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + ContourLevelStep = 0.5, + LabelStep = 2 + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks LabelStep = 2, ContourLevelStep = 0.33")] + public static PlotModel PeaksLabelStep2LevelStep033() + { + var model = new PlotModel { Title = "Peaks LabelStep = 2, ContourLevelStep = 0.33" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + ContourLevelStep = 0.33, + LabelStep = 2 + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks LabelStep = 3, ContourLevelStep = 1")] + public static PlotModel PeaksLabelStep3() + { + var model = new PlotModel { Title = "Peaks LabelStep = 3, ContourLevelStep = 1" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + LabelStep = 3 + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks MultiLabel")] + public static PlotModel PeaksMultiLabel() + { + var model = new PlotModel { Title = "Peaks MultiLabel" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + MultiLabel = true + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks LabelSpacing = 400")] + public static PlotModel PeaksLabelSpacing400() + { + var model = new PlotModel { Title = "Peaks LabelSpacing = 400" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + MultiLabel = true, + LabelSpacing = 400 + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks (different contour colors)")] + [DocumentationExample("Series/ContourSeries")] + public static PlotModel PeaksWithColors() + { + var model = new PlotModel { Title = "Peaks" }; + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.05), + ContourColors = new[] { OxyColors.SeaGreen, OxyColors.RoyalBlue, OxyColors.IndianRed } + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Peaks (wide array)")] + public static PlotModel WideArrayPeaks() + { + var model = new PlotModel { Title = "Peaks" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -3.16262, Maximum = 3.162 }); + + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-1, 1, 0.05) + }; + cs.Data = ArrayBuilder.Evaluate(peaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Subtitle = cs.Data.GetLength(0) + "×" + cs.Data.GetLength(1); + model.Series.Add(cs); + return model; + } + + [Example("Open Contours")] + public static PlotModel OpenContours() + { + var model = new PlotModel(); + var cs = new ContourSeries + { + ColumnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05), + RowCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.05) + }; + + cs.Data = ArrayBuilder.Evaluate(openContours, cs.ColumnCoordinates, cs.RowCoordinates); + model.Series.Add(cs); + return model; + } + + [Example("Logarithmic Peaks")] + public static PlotModel LogPeaks() + { + Func logPeaks = (x, y) => peaks(Math.Log(x) / 10, Math.Log(y) / 10); + + var model = new PlotModel(); + var coordinates = ArrayBuilder.CreateVector(-3, 3, 0.05); + for (var i = 0; i < coordinates.Length; i++) + { + coordinates[i] = Math.Exp(coordinates[i] * 10); + } + + var cs = new ContourSeries + { + ColumnCoordinates = coordinates, + RowCoordinates = coordinates + }; + + cs.Data = ArrayBuilder.Evaluate(logPeaks, cs.ColumnCoordinates, cs.RowCoordinates); + model.Series.Add(cs); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Left }); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/ErrorBarSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/ErrorBarSeriesExamples.cs new file mode 100644 index 0000000..c1f1191 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/ErrorBarSeriesExamples.cs @@ -0,0 +1,76 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("ErrorBarSeries"), Tags("Series")] + public class ErrorBarSeriesExamples + { + [Example("ErrorBarSeries")] + [DocumentationExample("Series/ErrorBarSeries")] + public static PlotModel GetErrorBarSeries() + { + var model = new PlotModel + { + Title = "ErrorBarSeries" + }; + + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + LegendOrientation = LegendOrientation.Horizontal, + LegendBorderThickness = 0 + }; + + model.Legends.Add(l); + + var s1 = new ErrorBarSeries { Title = "Series 1", IsStacked = false, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s1.Items.Add(new ErrorBarItem { Value = 25, Error = 2 }); + s1.Items.Add(new ErrorBarItem { Value = 137, Error = 25 }); + s1.Items.Add(new ErrorBarItem { Value = 18, Error = 4 }); + s1.Items.Add(new ErrorBarItem { Value = 40, Error = 29 }); + + var s2 = new ErrorBarSeries { Title = "Series 2", IsStacked = false, StrokeColor = OxyColors.Black, StrokeThickness = 1 }; + s2.Items.Add(new ErrorBarItem { Value = 35, Error = 20 }); + s2.Items.Add(new ErrorBarItem { Value = 17, Error = 7 }); + s2.Items.Add(new ErrorBarItem { Value = 118, Error = 44 }); + s2.Items.Add(new ErrorBarItem { Value = 49, Error = 29 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Category A"); + categoryAxis.Labels.Add("Category B"); + categoryAxis.Labels.Add("Category C"); + categoryAxis.Labels.Add("Category D"); + + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0 }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + + return model; + } + + [Example("ErrorBarSeries (thick error lines)")] + public static PlotModel GetErrorBarSeriesThickErrorLines() + { + var model = GetErrorBarSeries(); + foreach (ErrorBarSeries s in model.Series) + { + s.ErrorWidth = 0; + s.ErrorStrokeThickness = 4; + } + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/ExtrapolationLineSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/ExtrapolationLineSeriesExamples.cs new file mode 100644 index 0000000..627e670 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/ExtrapolationLineSeriesExamples.cs @@ -0,0 +1,497 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for the ExtrapolationLineSeries. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary.Series +{ + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Legends; + using OxyPlot.Series; + + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// Provides examples for the . + /// + [Examples("ExtrapolationLineSeries")] + [Tags("Series")] + public static class ExtrapolationLineSeriesExamples + { + /// + /// Creates an example showing a line fit which is extrapolated + /// beyond the range given by the data points. + /// + /// A . + [Example("Line Fit (Ignore Extrapolation For Scaling)")] + public static PlotModel ExtrapolatedLineSeries() + { + var model = new PlotModel { Title = "Line Fit" }; + + var scatterSeries = new ScatterSeries() + { + Title = "Data", + }; + + scatterSeries.Points.Add(new ScatterPoint(3, 1.4)); + scatterSeries.Points.Add(new ScatterPoint(4, 1.3)); + scatterSeries.Points.Add(new ScatterPoint(5, 1.6)); + scatterSeries.Points.Add(new ScatterPoint(6, 2.3)); + scatterSeries.Points.Add(new ScatterPoint(7, 2.2)); + scatterSeries.Points.Add(new ScatterPoint(8, 2.5)); + scatterSeries.Points.Add(new ScatterPoint(9, 2.9)); + scatterSeries.Points.Add(new ScatterPoint(10, 3.1)); + scatterSeries.Points.Add(new ScatterPoint(11, 3.1)); + scatterSeries.Points.Add(new ScatterPoint(12, 3.8)); + + model.Series.Add(scatterSeries); + + CalculateLinearRegressionParameters(scatterSeries.Points, out double slope, out double intercept); + + var lineSeries = new ExtrapolationLineSeries + { + Title = "Fit", + Color = OxyColors.Black, + LineStyle = LineStyle.Solid, + ExtrapolationColor = OxyColors.DarkGray, + ExtrapolationLineStyle = LineStyle.Dash, + StrokeThickness = 3, + IgnoreExtraplotationForScaling = true, + }; + + lineSeries.Intervals.Add(new DataRange(double.NegativeInfinity, scatterSeries.Points.Select(p => p.X).Min())); + lineSeries.Intervals.Add(new DataRange(scatterSeries.Points.Select(p => p.X).Max(), double.PositiveInfinity)); + + var fitPoints = Enumerable + .Range(-100, 200) + .Select(x => new DataPoint(x, (slope * x) + intercept)); + + lineSeries.Points.AddRange(fitPoints); + model.Series.Add(lineSeries); + + var legend = new Legend + { + LegendPosition = LegendPosition.BottomRight, + }; + + model.Legends.Add(legend); + + return model; + } + + /// + /// Creates an example showing a third-order polynomial with extra- and interpolation style. + /// + /// A . + [Example("Interpolation")] + public static PlotModel InterpolationStyleLineSeries() + { + var model = new PlotModel { Title = "Interpolation" }; + + var lineSeries = new ExtrapolationLineSeries + { + Title = "Third Order Polynomial", + Color = OxyColors.Black, + LineStyle = LineStyle.Dash, + ExtrapolationColor = OxyColors.Gray, + ExtrapolationLineStyle = LineStyle.Dot, + StrokeThickness = 3, + }; + + lineSeries.Intervals.Add(new DataRange(double.NegativeInfinity, -15)); + lineSeries.Intervals.Add(new DataRange(10, 30)); + lineSeries.Intervals.Add(new DataRange(55, double.PositiveInfinity)); + + var coefficients = new double[] { 0.1, -6.0, -12, 0 }; + + double PolynomialValue(double x, IEnumerable coeff) + { + // Horner's schema + return coeff.Aggregate((acc, coefficient) => (acc * x) + coefficient); + } + + var points = Enumerable + .Range(-30, 100) + .Select(x => new DataPoint(x, PolynomialValue(x, coefficients))); + + lineSeries.Points.AddRange(points); + + model.Series.Add(lineSeries); + + var legend = new Legend + { + LegendPosition = LegendPosition.TopCenter, + }; + + model.Legends.Add(legend); + + return model; + } + + /// + /// Creates an example showing a third-order polynomial with extra- and + /// interpolation style and an inverted y-axis. + /// + /// A . + [Example("Interpolation (Y Axis reversed)")] + public static PlotModel TwoColorLineSeriesReversed() + { + return InterpolationStyleLineSeries().ReverseYAxis(); + } + + /// + /// Creates an example where the provided extrapolation + /// intervals overlap with each other. + /// + /// A . + [Example("Intersecting Intervals")] + public static PlotModel IntersectingIntervals() + { + var model = new PlotModel { Title = "Intersecting Intervals" }; + + var i1 = new DataRange(-20, 20); + var i2 = new DataRange(0, 30); + var i3 = new DataRange(10, 40); + + var lineSeries = new ExtrapolationLineSeries + { + Title = $"Overlapping intervals {i1}, {i2}, {i3}", + Color = OxyColors.Black, + LineStyle = LineStyle.Solid, + ExtrapolationColor = OxyColors.Gray, + ExtrapolationLineStyle = LineStyle.Dot, + StrokeThickness = 3, + }; + + lineSeries.Intervals.Add(i1); + lineSeries.Intervals.Add(i2); + lineSeries.Intervals.Add(i3); + + var coefficients = new double[] { 0.1, -6.0, -12, 0 }; + + double PolynomialValue(double x, IEnumerable coeff) + { + // Horner's schema + return coeff.Aggregate((acc, coefficient) => (acc * x) + coefficient); + } + + var points = Enumerable + .Range(-30, 100) + .Select(x => new DataPoint(x, PolynomialValue(x, coefficients))); + + lineSeries.Points.AddRange(points); + + model.Series.Add(lineSeries); + + var legend = new Legend + { + LegendPosition = LegendPosition.TopCenter, + }; + + model.Legends.Add(legend); + + return model; + } + + /// + /// Creates an example showing a line using custom dash arrays for the + /// normal and extrapolated parts of the curve. + /// + /// A . + [Example("Custom Dashes")] + public static PlotModel CustomDashes() + { + var model = new PlotModel { Title = "Custom Dashes" }; + + var lineSeries = new ExtrapolationLineSeries + { + Title = "y = 5", + Color = OxyColors.Black, + LineStyle = LineStyle.Dash, + Dashes = new double[] { 5, 1 }, + ExtrapolationColor = OxyColors.Gray, + ExtrapolationLineStyle = LineStyle.Dot, + ExtrapolationDashes = new double[] { 1, 5 }, + StrokeThickness = 3, + }; + + lineSeries.Intervals.Add(new DataRange(double.NegativeInfinity, 0)); + + var points = Enumerable + .Range(-100, 200) + .Select(x => new DataPoint(x, 5)); + + lineSeries.Points.AddRange(points); + + model.Series.Add(lineSeries); + + var legend = new Legend + { + LegendPosition = LegendPosition.TopCenter, + }; + + model.Legends.Add(legend); + + return model; + } + + /// + /// Creates an example to test the performance with 100000 points and 100 intervals. + /// + /// A . + [Example("Many Intervals")] + public static PlotModel ManyIntervals() + { + var model = new PlotModel { Title = "ManyIntervals" }; + + var lineSeries = new ExtrapolationLineSeries + { + Title = "y = x", + Color = OxyColors.Red, + LineStyle = LineStyle.Solid, + ExtrapolationLineStyle = LineStyle.Solid, + StrokeThickness = 3, + IgnoreExtraplotationForScaling = true, + }; + + lineSeries.Intervals.Add(new DataRange(-1000, 10_000)); + + var intervals = Enumerable + .Range(0, 98) + .Select(x => new DataRange(1000 * x, (1000 * x) + 500)); + + foreach(var interval in intervals) + lineSeries.Intervals.Add(interval); + + lineSeries.Intervals.Add(new DataRange(200_000, double.PositiveInfinity)); + + var points = Enumerable + .Range(0, 100_000) + .Select(x => new DataPoint(x, x)); + + lineSeries.Points.AddRange(points); + + model.Series.Add(lineSeries); + + var legend = new Legend + { + LegendPosition = LegendPosition.TopCenter, + }; + + model.Legends.Add(legend); + + return model; + } + + /// + /// Creates an example where Moore's law is fitted and + /// extrapolated to the future. + /// + /// A . + [Example("Moore's Law")] + public static PlotModel MooresLaw() + { + var model = new PlotModel { Title = "Moore's Law" }; + + var scatterSeries = new ScatterSeries() + { + Title = "Data", + }; + + scatterSeries.Points.AddRange(GetPointForMooresLaw()); + + model.Series.Add(scatterSeries); + + model.Axes.Add(new LinearAxis { Title = "Year", Position = AxisPosition.Bottom }); + model.Axes.Add(new LogarithmicAxis { Title = "Transistors (in thousands)", Position = AxisPosition.Left }); + + CalculateLinearRegressionParameters(scatterSeries.Points.Select(p => new ScatterPoint(p.X, Math.Log10(p.Y))), out double slope, out double intercept); + + var lineSeries = new ExtrapolationLineSeries + { + Title = "Fit and Extrapolation", + Color = OxyColors.Black, + LineStyle = LineStyle.Solid, + ExtrapolationColor = OxyColors.Blue, + ExtrapolationLineStyle = LineStyle.Dot, + StrokeThickness = 3, + }; + + lineSeries.Intervals.Add(new DataRange(2015, double.PositiveInfinity)); + + var fitPoints = Enumerable + .Range(1970, 55) + .Select(x => new DataPoint(x, Math.Pow(10, (slope * x) + intercept))); + + lineSeries.Points.AddRange(fitPoints); + + model.Series.Add(lineSeries); + + var legend = new Legend + { + LegendPosition = LegendPosition.TopCenter, + }; + + model.Legends.Add(legend); + + return model; + } + + /// + /// Sets the slope and intercept of a linear regression line through the provided points. + /// + private static void CalculateLinearRegressionParameters(IEnumerable points, out double slope, out double intercept) + { + if (points == null) + { + throw new ArgumentNullException(nameof(points)); + } + + if (points.Count() < 2) + { + throw new ArgumentException("at least two points required", nameof(points)); + } + + var meanX = points.Select(p => p.X).Average(); + var meanY = points.Select(p => p.Y).Average(); + + var cov = Covariance(points, meanX, meanY); + var var2_x = Variance2(points.Select(p => p.X)); + + slope = cov / var2_x; + intercept = meanY - (slope * meanX); + } + + /// + /// Returns the covariance between the points x and y values. + /// + private static double Covariance(IEnumerable points, double meanX, double meanY) + { + var res = points.Sum(p => p.X * p.Y); + + res -= points.Count() * meanX * meanY; + res /= points.Count() - 1; + + return res; + } + + /// + /// Returns the squared variance of a quantity. + /// + private static double Variance2(IEnumerable values) + { + var mean = values.Average(); + + var res = values.Sum(x => x * x); + + res -= values.Count() * mean * mean; + res /= values.Count() - 1; + + return res; + } + + /// + /// Returns data points to demonstrate Moore's law. + /// Source: https://www.karlrupp.net/2015/06/40-years-of-microprocessor-trend-data/. + /// + private static IEnumerable GetPointForMooresLaw() + { + yield return new ScatterPoint(1971.875, 2.30824152676); + yield return new ScatterPoint(1972.30769231, 3.55452235561); + yield return new ScatterPoint(1974.32692308, 6.09756235221); + yield return new ScatterPoint(1979.56730769, 29.1637757405); + yield return new ScatterPoint(1982.30769231, 135.772714211); + yield return new ScatterPoint(1985.91346154, 273.841963426); + yield return new ScatterPoint(1986.25, 109.411381058); + yield return new ScatterPoint(1988.65384615, 121.881418484); + yield return new ScatterPoint(1989.47115385, 1207.90074743); + yield return new ScatterPoint(1990.57692308, 1207.90074743); + yield return new ScatterPoint(1992.40384615, 1207.90074743); + yield return new ScatterPoint(1992.69230769, 3105.90022362); + yield return new ScatterPoint(1992.69230769, 1113.97385999); + yield return new ScatterPoint(1993.02884615, 1715.43789634); + yield return new ScatterPoint(1993.41346154, 3105.90022362); + yield return new ScatterPoint(1993.41346154, 922.239565104); + yield return new ScatterPoint(1994.71153846, 1910.95297497); + yield return new ScatterPoint(1994.71153846, 2788.12666541); + yield return new ScatterPoint(1995.43269231, 9646.61619911); + yield return new ScatterPoint(1995.72115385, 3105.90022362); + yield return new ScatterPoint(1996.15384615, 5473.70326288); + yield return new ScatterPoint(1996.34615385, 6792.52507006); + yield return new ScatterPoint(1996.34615385, 3651.74127255); + yield return new ScatterPoint(1996.44230769, 4293.51021008); + yield return new ScatterPoint(1996.82692308, 9646.61619911); + yield return new ScatterPoint(1997.35576923, 5473.70326288); + yield return new ScatterPoint(1997.45192308, 3554.52235561); + yield return new ScatterPoint(1997.54807692, 8896.4911282); + yield return new ScatterPoint(1997.64423077, 7566.6953714); + yield return new ScatterPoint(1998.89423077, 15261.3780258); + yield return new ScatterPoint(1999.13461538, 9389.79801048); + yield return new ScatterPoint(1999.18269231, 6978.3058486); + yield return new ScatterPoint(1999.47115385, 9389.79801048); + yield return new ScatterPoint(1999.47115385, 21673.9216957); + yield return new ScatterPoint(2000.19230769, 22266.7201035); + yield return new ScatterPoint(2000.67307692, 28387.3596476); + yield return new ScatterPoint(2000.67307692, 37180.2666391); + yield return new ScatterPoint(2001.10576923, 29163.7757405); + yield return new ScatterPoint(2001.20192308, 42550.6550247); + yield return new ScatterPoint(2001.68269231, 25482.9674798); + yield return new ScatterPoint(2001.82692308, 37180.2666391); + yield return new ScatterPoint(2002.40384615, 55730.6040127); + yield return new ScatterPoint(2002.78846154, 38197.1754928); + yield return new ScatterPoint(2002.88461538, 220673.406908); + yield return new ScatterPoint(2003.41346154, 151247.254531); + yield return new ScatterPoint(2003.50961538, 54246.9093701); + yield return new ScatterPoint(2003.65384615, 106498.563535); + yield return new ScatterPoint(2004.80769231, 125214.968907); + yield return new ScatterPoint(2004.80769231, 106498.563535); + yield return new ScatterPoint(2004.80769231, 273841.963426); + yield return new ScatterPoint(2005.72115385, 232909.659246); + yield return new ScatterPoint(2005.81730769, 112403.866377); + yield return new ScatterPoint(2005.96153846, 305052.789027); + yield return new ScatterPoint(2006.05769231, 115478.198469); + yield return new ScatterPoint(2006.875, 378551.524926); + yield return new ScatterPoint(2006.875, 155383.983127); + yield return new ScatterPoint(2006.92307692, 245824.406892); + yield return new ScatterPoint(2006.97115385, 296931.48482); + yield return new ScatterPoint(2006.97115385, 582941.534714); + yield return new ScatterPoint(2007.06730769, 151247.254531); + yield return new ScatterPoint(2007.64423077, 582941.534714); + yield return new ScatterPoint(2007.74038462, 232909.659246); + yield return new ScatterPoint(2007.78846154, 805842.187761); + yield return new ScatterPoint(2007.83653846, 115478.198469); + yield return new ScatterPoint(2007.98076923, 509367.521678); + yield return new ScatterPoint(2008.22115385, 445079.406236); + yield return new ScatterPoint(2008.46153846, 410469.838044); + yield return new ScatterPoint(2009.18269231, 457252.669897); + yield return new ScatterPoint(2009.27884615, 784388.558145); + yield return new ScatterPoint(2009.66346154, 2308241.52676); + yield return new ScatterPoint(2009.71153846, 1910952.97497); + yield return new ScatterPoint(2010.19230769, 410469.838044); + yield return new ScatterPoint(2010.38461538, 1309747.2643); + yield return new ScatterPoint(2011.16, 1170000); + yield return new ScatterPoint(2011.32, 2600000); + yield return new ScatterPoint(2011.9, 1200000); + yield return new ScatterPoint(2012.40, 2400000); + yield return new ScatterPoint(2012.41, 2300000); + yield return new ScatterPoint(2012.7, 2100000); + yield return new ScatterPoint(2012.9, 1200000); + yield return new ScatterPoint(2013.4, 5000000); + yield return new ScatterPoint(2013.8, 4300000); + yield return new ScatterPoint(2014.16, 4300000); + yield return new ScatterPoint(2014.5, 4200000); + yield return new ScatterPoint(2014.8, 2600000); + yield return new ScatterPoint(2014.81, 3800000); + yield return new ScatterPoint(2014.82, 5700000); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/CandleStickAndVolumeSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/CandleStickAndVolumeSeriesExamples.cs new file mode 100644 index 0000000..74e0a84 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/CandleStickAndVolumeSeriesExamples.cs @@ -0,0 +1,235 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Linq; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("CandleStickAndVolumeSeries")] + [Tags("Series")] + public static class CandleStickAndVolumeSeriesExamples + { + [Example("Candles + Volume (combined volume), adjusting Y-axis")] + public static Example CombinedVolume_Adjusting() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (combined volume)", + VolumeStyle.Combined, + naturalY: false, + naturalV: false); + } + + [Example("Candles + Volume (combined volume), natural Y-axis")] + public static Example CombinedVolume_Natural() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (combined volume)", + VolumeStyle.Combined, + naturalY: true, + naturalV: true); + } + + [Example("Candles + Volume (stacked volume), adjusting Y-axis")] + public static Example StackedVolume_Adjusting() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (stacked volume)", + VolumeStyle.Stacked, + naturalY: false, + naturalV: false); + } + + [Example("Candles + Volume (stacked volume), natural Y-axis")] + public static Example StackedVolume_Natural() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (stacked volume)", + VolumeStyle.Stacked, + naturalY: true, + naturalV: true); + } + + [Example("Candles + Volume (+/- volume), adjusting Y-axis")] + public static Example PosNegVolume_Adjusting() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (+/- volume)", + VolumeStyle.PositiveNegative, + naturalY: false, + naturalV: false); + } + + [Example("Candles + Volume (+/- volume), natural Y-axis")] + public static Example PosNegVolume_Natural() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (+/- volume)", + VolumeStyle.PositiveNegative, + naturalY: true, + naturalV: true); + } + + [Example("Candles + Volume (volume not shown), adjusting Y-axis")] + public static Example NoVolume_Adjusting() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (volume not shown)", + VolumeStyle.None, + naturalY: false, + naturalV: false); + } + + [Example("Candles + Volume (volume not shown), natural Y-axis")] + public static Example NoVolume_Natural() + { + return CreateCandleStickAndVolumeSeriesExample( + "Candles + Volume (volume not shown)", + VolumeStyle.None, + naturalY: true, + naturalV: true); + } + + /// + /// Creates the candle stick and volume series example. + /// + /// The candle stick and volume series example. + /// Title. + /// Style. + /// N. + /// If set to true natural y. + /// If set to true natural v. + private static Example CreateCandleStickAndVolumeSeriesExample( + string title, + VolumeStyle style, + int n = 10000, + bool naturalY = false, + bool naturalV = false) + { + var pm = new PlotModel { Title = title }; + + var series = new CandleStickAndVolumeSeries + { + PositiveColor = OxyColors.DarkGreen, + NegativeColor = OxyColors.Red, + PositiveHollow = false, + NegativeHollow = false, + SeparatorColor = OxyColors.Gray, + SeparatorLineStyle = LineStyle.Dash, + VolumeStyle = style + }; + + // create bars + foreach (var bar in OhlcvItemGenerator.MRProcess(n)) + { + series.Append(bar); + } + + // create visible window + var Istart = n - 200; + var Iend = n - 120; + var Ymin = series.Items.Skip(Istart).Take(Iend - Istart + 1).Select(x => x.Low).Min(); + var Ymax = series.Items.Skip(Istart).Take(Iend - Istart + 1).Select(x => x.High).Max(); + var Xmin = series.Items[Istart].X; + var Xmax = series.Items[Iend].X; + + // setup axes + var timeAxis = new DateTimeAxis + { + Position = AxisPosition.Bottom, + Minimum = Xmin, + Maximum = Xmax + }; + var barAxis = new LinearAxis + { + Position = AxisPosition.Left, + Key = series.BarAxisKey, + StartPosition = 0.25, + EndPosition = 1.0, + Minimum = naturalY ? double.NaN : Ymin, + Maximum = naturalY ? double.NaN : Ymax + }; + var volAxis = new LinearAxis + { + Position = AxisPosition.Left, + Key = series.VolumeAxisKey, + StartPosition = 0.0, + EndPosition = 0.22, + Minimum = naturalV ? double.NaN : 0, + Maximum = naturalV ? double.NaN : 5000 + }; + + switch (style) + { + case VolumeStyle.None: + barAxis.Key = null; + barAxis.StartPosition = 0.0; + pm.Axes.Add(timeAxis); + pm.Axes.Add(barAxis); + break; + + case VolumeStyle.Combined: + case VolumeStyle.Stacked: + pm.Axes.Add(timeAxis); + pm.Axes.Add(barAxis); + pm.Axes.Add(volAxis); + break; + + case VolumeStyle.PositiveNegative: + volAxis.Minimum = naturalV ? double.NaN : -5000; + pm.Axes.Add(timeAxis); + pm.Axes.Add(barAxis); + pm.Axes.Add(volAxis); + break; + } + + pm.Series.Add(series); + + if (naturalY == false) + { + timeAxis.AxisChanged += (sender, e) => AdjustYExtent(series, timeAxis, barAxis); + } + + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); + return new Example(pm, controller); + } + + /// + /// Adjusts the Y extent. + /// + /// Series. + /// Xaxis. + /// Yaxis. + private static void AdjustYExtent(CandleStickAndVolumeSeries series, DateTimeAxis xaxis, LinearAxis yaxis) + { + var xmin = xaxis.ActualMinimum; + var xmax = xaxis.ActualMaximum; + + var istart = series.FindByX(xmin); + var iend = series.FindByX(xmax, istart); + + var ymin = double.MaxValue; + var ymax = double.MinValue; + for (int i = istart; i <= iend; i++) + { + var bar = series.Items[i]; + ymin = Math.Min(ymin, bar.Low); + ymax = Math.Max(ymax, bar.High); + } + + var extent = ymax - ymin; + var margin = extent * 0.10; + + yaxis.Zoom(ymin - margin, ymax + margin); + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/CandleStickSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/CandleStickSeriesExamples.cs new file mode 100644 index 0000000..f2dad2b --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/CandleStickSeriesExamples.cs @@ -0,0 +1,179 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Linq; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("CandleStickSeries"), Tags("Series")] + public static class CandleStickSeriesExamples + { + [Example("Large Data Set (wide window)")] + public static Example LargeDataSetWide() + { + var pm = new PlotModel { Title = "Large Data Set (wide window)" }; + + var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom }; + pm.Axes.Add(timeSpanAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Left }; + pm.Axes.Add(linearAxis1); + var n = 1000000; + var items = HighLowItemGenerator.MRProcess(n).ToArray(); + var series = new CandleStickSeries + { + Color = OxyColors.Black, + IncreasingColor = OxyColors.DarkGreen, + DecreasingColor = OxyColors.Red, + DataFieldX = "Time", + DataFieldHigh = "H", + DataFieldLow = "L", + DataFieldOpen = "O", + DataFieldClose = "C", + TrackerFormatString = + "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}", + ItemsSource = items + }; + + timeSpanAxis1.Minimum = items[n - 200].X; + timeSpanAxis1.Maximum = items[n - 130].X; + + linearAxis1.Minimum = items.Skip(n - 200).Take(70).Select(x => x.Low).Min(); + linearAxis1.Maximum = items.Skip(n - 200).Take(70).Select(x => x.High).Max(); + + pm.Series.Add(series); + + timeSpanAxis1.AxisChanged += (sender, e) => AdjustYExtent(series, timeSpanAxis1, linearAxis1); + + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); + return new Example(pm, controller); + } + + [Example("Large Data Set (narrow window)")] + public static Example LargeDataSetNarrow() + { + var pm = new PlotModel { Title = "Large Data Set (narrow window)" }; + + var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom }; + pm.Axes.Add(timeSpanAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Left }; + pm.Axes.Add(linearAxis1); + var n = 1000000; + var items = HighLowItemGenerator.MRProcess(n).ToArray(); + var series = new CandleStickSeries + { + Color = OxyColors.Black, + IncreasingColor = OxyColors.DarkGreen, + DecreasingColor = OxyColors.Red, + TrackerFormatString = + "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}", + ItemsSource = items + }; + + + timeSpanAxis1.Minimum = items[0].X; + timeSpanAxis1.Maximum = items[29].X; + + linearAxis1.Minimum = items.Take(30).Select(x => x.Low).Min(); + linearAxis1.Maximum = items.Take(30).Select(x => x.High).Max(); + + pm.Series.Add(series); + + timeSpanAxis1.AxisChanged += (sender, e) => AdjustYExtent(series, timeSpanAxis1, linearAxis1); + + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); + return new Example(pm, controller); + } + + [Example("Small Set")] + public static Example SmallDataSet() + { + var pm = new PlotModel { Title = "Small Data Set" }; + + var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom }; + pm.Axes.Add(timeSpanAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Left }; + pm.Axes.Add(linearAxis1); + var n = 100; + var items = HighLowItemGenerator.MRProcess(n).ToArray(); + var series = new CandleStickSeries + { + Color = OxyColors.Black, + IncreasingColor = OxyColors.DarkGreen, + DecreasingColor = OxyColors.Red, + DataFieldX = "X", + DataFieldHigh = "High", + DataFieldLow = "Low", + DataFieldOpen = "Open", + DataFieldClose = "Close", + TrackerFormatString = + "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}", + ItemsSource = items + }; + + pm.Series.Add(series); + + timeSpanAxis1.AxisChanged += (sender, e) => AdjustYExtent(series, timeSpanAxis1, linearAxis1); + + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); + return new Example(pm, controller); + } + + [Example("Simple CandleStickSeries example")] + public static PlotModel SimpleExample() + { + var startTimeValue = DateTimeAxis.ToDouble(new DateTime(2016, 1, 1)); + var pm = new PlotModel { Title = "Simple CandleStickSeries example" }; + pm.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, Minimum = startTimeValue - 7, Maximum = startTimeValue + 7 }); + pm.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var series = new CandleStickSeries(); + series.Items.Add(new HighLowItem(startTimeValue, 100, 80, 92, 94)); + series.Items.Add(new HighLowItem(startTimeValue + 1, 102, 77, 94, 93)); + series.Items.Add(new HighLowItem(startTimeValue + 2, 99, 85, 93, 93)); + pm.Series.Add(series); + return pm; + } + + /// + /// Adjusts the Y extent. + /// + /// Series. + /// Xaxis. + /// Yaxis. + private static void AdjustYExtent(CandleStickSeries series, DateTimeAxis xaxis, LinearAxis yaxis) + { + var xmin = xaxis.ActualMinimum; + var xmax = xaxis.ActualMaximum; + + var istart = series.FindByX(xmin); + var iend = series.FindByX(xmax, istart); + + var ymin = double.MaxValue; + var ymax = double.MinValue; + for (int i = istart; i <= iend; i++) + { + var bar = series.Items[i]; + ymin = Math.Min(ymin, bar.Low); + ymax = Math.Max(ymax, bar.High); + } + + var extent = ymax - ymin; + var margin = extent * 0.10; + + yaxis.Zoom(ymin - margin, ymax + margin); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/HighLowItemGenerator.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/HighLowItemGenerator.cs new file mode 100644 index 0000000..be8dd43 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/HighLowItemGenerator.cs @@ -0,0 +1,197 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Creates realistic high/low items. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Creates realistic high/low items. + /// + public static class HighLowItemGenerator + { + /// + /// The random number generator. + /// + private static readonly Random Rand = new Random(); + + /// + /// Creates bars governed by a MR process + /// + /// The process. + /// N. + /// X0. + /// Csigma. + /// Esigma. + /// Kappa. + public static IEnumerable MRProcess( + int n, + double x0 = 100.0, + double csigma = 0.50, + double esigma = 0.70, + double kappa = 0.01) + { + double x = x0; + + var baseT = DateTime.UtcNow; + for (int ti = 0; ti < n; ti++) + { + var dx_c = -kappa * (x - x0) + RandomNormal(0, csigma); + var dx_1 = -kappa * (x - x0) + RandomNormal(0, esigma); + var dx_2 = -kappa * (x - x0) + RandomNormal(0, esigma); + + var open = x; + var close = x = x + dx_c; + var low = Min(open, close, open + dx_1, open + dx_2); + var high = Max(open, close, open + dx_1, open + dx_2); + + var nowT = baseT.AddSeconds(ti); + var t = DateTimeAxis.ToDouble(nowT); + yield return new HighLowItem(t, high, low, open, close); + } + } + + /// + /// Finds the minimum of the specified a, b, c and d. + /// + /// A. + /// B. + /// C. + /// D. + /// The minimum. + private static double Min(double a, double b, double c, double d) + { + return Math.Min(a, Math.Min(b, Math.Min(c, d))); + } + + /// + /// Finds the maximum of the specified a, b, c and d. + /// + /// A. + /// B. + /// C. + /// D. + /// The maximum. + private static double Max(double a, double b, double c, double d) + { + return Math.Max(a, Math.Max(b, Math.Max(c, d))); + } + + /// + /// Get random normal + /// + /// Mu. + /// Sigma. + private static double RandomNormal(double mu, double sigma) + { + return InverseCumNormal(Rand.NextDouble(), mu, sigma); + } + + /// + /// Fast approximation for inverse cum normal + /// + /// probability + /// Mean + /// std dev + private static double InverseCumNormal(double p, double mu, double sigma) + { + const double A1 = -3.969683028665376e+01; + const double A2 = 2.209460984245205e+02; + const double A3 = -2.759285104469687e+02; + const double A4 = 1.383577518672690e+02; + const double A5 = -3.066479806614716e+01; + const double A6 = 2.506628277459239e+00; + + const double B1 = -5.447609879822406e+01; + const double B2 = 1.615858368580409e+02; + const double B3 = -1.556989798598866e+02; + const double B4 = 6.680131188771972e+01; + const double B5 = -1.328068155288572e+01; + + const double C1 = -7.784894002430293e-03; + const double C2 = -3.223964580411365e-01; + const double C3 = -2.400758277161838e+00; + const double C4 = -2.549732539343734e+00; + const double C5 = 4.374664141464968e+00; + const double C6 = 2.938163982698783e+00; + + const double D1 = 7.784695709041462e-03; + const double D2 = 3.224671290700398e-01; + const double D3 = 2.445134137142996e+00; + const double D4 = 3.754408661907416e+00; + + const double Xlow = 0.02425; + const double Xhigh = 1.0 - Xlow; + + double z, r; + + if (p < Xlow) + { + // Rational approximation for the lower region 0 + /// Cumulative for a N(0,1) distribution + /// + /// The n0. + /// The x coordinate. + private static double CumN0(double x) + { + const double B1 = 0.319381530; + const double B2 = -0.356563782; + const double B3 = 1.781477937; + const double B4 = -1.821255978; + const double B5 = 1.330274429; + const double P = 0.2316419; + const double C = 0.39894228; + + if (x >= 0.0) + { + double t = 1.0 / (1.0 + (P * x)); + return (1.0 - C * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * B5 + B4) + B3) + B2) + B1)); + } + else + { + double t = 1.0 / (1.0 - P * x); + return (C * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * B5 + B4) + B3) + B2) + B1)); + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/HighLowSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/HighLowSeriesExamples.cs new file mode 100644 index 0000000..3e02655 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/HighLowSeriesExamples.cs @@ -0,0 +1,86 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("HighLowSeries"), Tags("Series")] + public static class HighLowSeriesExamples + { + [Example("HighLowSeries")] + public static PlotModel HighLowSeries() + { + var model = new PlotModel { Title = "HighLowSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new HighLowSeries { Title = "HighLowSeries 1", Color = OxyColors.Black, }; + var r = new Random(314); + var price = 100.0; + for (int x = 0; x < 24; x++) + { + price = price + r.NextDouble() + 0.1; + var high = price + 10 + r.NextDouble() * 10; + var low = price - (10 + r.NextDouble() * 10); + var open = low + r.NextDouble() * (high - low); + var close = low + r.NextDouble() * (high - low); + s1.Items.Add(new HighLowItem(x, high, low, open, close)); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MaximumPadding = 0.3, MinimumPadding = 0.3 }); + + return model; + } + + [Example("HighLowSeries (reversed X Axis)")] + public static PlotModel HighLowSeriesReversedXAxis() + { + return HighLowSeries().ReverseXAxis(); + } + + [Example("HighLowSeries (DateTime axis)")] + public static PlotModel HighLowSeriesDateTimeAxis() + { + var m = new PlotModel(); + var x0 = DateTimeAxis.ToDouble(new DateTime(2013, 05, 04)); + var a = new DateTimeAxis + { + Position = AxisPosition.Bottom, + Minimum = x0 - 0.9, + Maximum = x0 + 1.9, + IntervalType = DateTimeIntervalType.Days, + MajorStep = 1, + MinorStep = 1, + StringFormat = "yyyy-MM-dd" + }; + m.Axes.Add(a); + var s = new HighLowSeries + { + TrackerFormatString = + "X: {1:yyyy-MM-dd}\nHigh: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}" + }; + + s.Items.Add(new HighLowItem(x0, 14, 10, 13, 12.4)); + s.Items.Add(new HighLowItem(x0 + 1, 17, 8, 12.4, 16.3)); + m.Series.Add(s); + + return m; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/OhlcvItemGenerator.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/OhlcvItemGenerator.cs new file mode 100644 index 0000000..307a703 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/OhlcvItemGenerator.cs @@ -0,0 +1,211 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Creates realistic OHLCV items. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Creates realistic OHLCV items. + /// + public static class OhlcvItemGenerator + { + /// + /// The random number generator. + /// + private static readonly Random Rand = new Random(); + + /// + /// Creates bars governed by a MR process. + /// + /// N. + /// X0. + /// V0. + /// Csigma. + /// Esigma. + /// Kappa. + /// + /// The process. + /// + public static IEnumerable MRProcess( + int n, + double x0 = 100.0, + double v0 = 500, + double csigma = 0.50, + double esigma = 0.75, + double kappa = 0.01) + { + double x = x0; + var baseT = DateTime.UtcNow; + for (int ti = 0; ti < n; ti++) + { + var dx_c = -kappa * (x - x0) + RandomNormal(0, csigma); + var dx_1 = -kappa * (x - x0) + RandomNormal(0, esigma); + var dx_2 = -kappa * (x - x0) + RandomNormal(0, esigma); + + var open = x; + var close = x = x + dx_c; + var low = Min(open, close, open + dx_1, open + dx_2); + var high = Max(open, close, open + dx_1, open + dx_2); + + var dp = close - open; + var v = v0 * Math.Exp(Math.Abs(dp) / csigma); + var dir = (dp < 0) ? + -Math.Min(-dp / esigma, 1.0) : + Math.Min(dp / esigma, 1.0); + + var skew = (dir + 1) / 2.0; + var buyvol = skew * v; + var sellvol = (1 - skew) * v; + + var nowT = baseT.AddSeconds(ti); + var t = DateTimeAxis.ToDouble(nowT); + yield return new OhlcvItem(t, open, high, low, close, buyvol, sellvol); + } + } + + /// + /// Finds the minimum of the specified a, b, c and d. + /// + /// A. + /// B. + /// C. + /// D. + /// The minimum. + private static double Min(double a, double b, double c, double d) + { + return Math.Min(a, Math.Min(b, Math.Min(c, d))); + } + + /// + /// Finds the maximum of the specified a, b, c and d. + /// + /// A. + /// B. + /// C. + /// D. + /// The maximum. + private static double Max(double a, double b, double c, double d) + { + return Math.Max(a, Math.Max(b, Math.Max(c, d))); + } + + /// + /// Gets random normal + /// + /// Mu. + /// Sigma. + /// + private static double RandomNormal(double mu, double sigma) + { + return InverseCumNormal(Rand.NextDouble(), mu, sigma); + } + + /// + /// Fast approximation for inverse cum normal + /// + /// probability + /// Mean + /// std dev + private static double InverseCumNormal(double p, double mu, double sigma) + { + const double A1 = -3.969683028665376e+01; + const double A2 = 2.209460984245205e+02; + const double A3 = -2.759285104469687e+02; + const double A4 = 1.383577518672690e+02; + const double A5 = -3.066479806614716e+01; + const double A6 = 2.506628277459239e+00; + + const double B1 = -5.447609879822406e+01; + const double B2 = 1.615858368580409e+02; + const double B3 = -1.556989798598866e+02; + const double B4 = 6.680131188771972e+01; + const double B5 = -1.328068155288572e+01; + + const double C1 = -7.784894002430293e-03; + const double C2 = -3.223964580411365e-01; + const double C3 = -2.400758277161838e+00; + const double C4 = -2.549732539343734e+00; + const double C5 = 4.374664141464968e+00; + const double C6 = 2.938163982698783e+00; + + const double D1 = 7.784695709041462e-03; + const double D2 = 3.224671290700398e-01; + const double D3 = 2.445134137142996e+00; + const double D4 = 3.754408661907416e+00; + + const double Xlow = 0.02425; + const double Xhigh = 1.0 - Xlow; + + double z, r; + + if (p < Xlow) + { + // Rational approximation for the lower region 0 + /// Cumulative for a N(0,1) distribution + /// + /// The n0. + /// The x coordinate. + private static double CumN0(double x) + { + const double B1 = 0.319381530; + const double B2 = -0.356563782; + const double B3 = 1.781477937; + const double B4 = -1.821255978; + const double B5 = 1.330274429; + const double P = 0.2316419; + const double C = 0.39894228; + + if (x >= 0.0) + { + double t = 1.0 / (1.0 + (P * x)); + return (1.0 - C * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * B5 + B4) + B3) + B2) + B1)); + } + else + { + double t = 1.0 / (1.0 - P * x); + return (C * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * B5 + B4) + B3) + B2) + B1)); + } + } + } +} \ No newline at end of file diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/OldCandleStickSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/OldCandleStickSeriesExamples.cs new file mode 100644 index 0000000..0bb749f --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/OldCandleStickSeriesExamples.cs @@ -0,0 +1,157 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("Old CandleStickSeries"), Tags("Series")] + [Obsolete] + public static class OldCandleStickSeriesExamples + { + [Example("CandleStickSeries")] + public static PlotModel CandleStickSeries() + { + var model = new PlotModel { Title = "CandleStickSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new OldCandleStickSeries + { + Title = "CandleStickSeries 1", + Color = OxyColors.Black, + }; + var r = new Random(314); + var price = 100.0; + for (int x = 0; x < 16; x++) + { + price = price + r.NextDouble() + 0.1; + var high = price + 10 + (r.NextDouble() * 10); + var low = price - (10 + (r.NextDouble() * 10)); + var open = low + (r.NextDouble() * (high - low)); + var close = low + (r.NextDouble() * (high - low)); + s1.Items.Add(new HighLowItem(x, high, low, open, close)); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MaximumPadding = 0.3, MinimumPadding = 0.3 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MaximumPadding = 0.03, MinimumPadding = 0.03 }); + + return model; + } + + [Example("CandleStickSeries (red/green)")] + public static PlotModel CandleStickSeriesRedGreen() + { + var model = CandleStickSeries(); + model.Title = "CandleStickSeries (red/green)"; + var s1 = (OldCandleStickSeries)model.Series[0]; + s1.IncreasingFill = OxyColors.DarkGreen; + s1.DecreasingFill = OxyColors.Red; + s1.ShadowEndColor = OxyColors.Gray; + s1.Color = OxyColors.Black; + return model; + } + + [Example("Minute data (DateTimeAxis)")] + public static PlotModel MinuteData_DateTimeAxis() + { + var pm = new PlotModel { Title = "Minute Data (DateTimeAxis)" }; + + var timeSpanAxis1 = new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "hh:mm" }; + pm.Axes.Add(timeSpanAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Left }; + pm.Axes.Add(linearAxis1); + var candleStickSeries = new OldCandleStickSeries + { + CandleWidth = 6, + Color = OxyColors.Black, + IncreasingFill = OxyColors.DarkGreen, + DecreasingFill = OxyColors.Red, + DataFieldX = "Time", + DataFieldHigh = "H", + DataFieldLow = "L", + DataFieldOpen = "O", + DataFieldClose = "C", + TrackerFormatString = "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}", + ItemsSource = lst + }; + pm.Series.Add(candleStickSeries); + return pm; + } + + private static List lst = new List + { + new MinuteRec { QTime = TimeSpan.Parse("06:31:00"), O = 1672.5000, H = 1673.5000, L = 1671.7500, C = 1672.7500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:32:00"), O = 1672.5000, H = 1673.5000, L = 1672.5000, C = 1672.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:33:00"), O = 1672.5000, H = 1672.7500, L = 1670.7500, C = 1671.2500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:34:00"), O = 1671.2500, H = 1671.2500, L = 1670.2500, C = 1670.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:35:00"), O = 1670.7500, H = 1671.7500, L = 1670.5000, C = 1671.2500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:36:00"), O = 1671.0000, H = 1672.5000, L = 1671.0000, C = 1672.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:37:00"), O = 1672.5000, H = 1673.0000, L = 1672.0000, C = 1673.0000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:38:00"), O = 1672.7500, H = 1673.2500, L = 1672.5000, C = 1672.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:39:00"), O = 1672.5000, H = 1672.7500, L = 1671.2500, C = 1671.2500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:40:00"), O = 1671.2500, H = 1672.5000, L = 1671.0000, C = 1672.0000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:41:00"), O = 1672.2500, H = 1672.5000, L = 1671.2500, C = 1672.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:42:00"), O = 1672.2500, H = 1672.5000, L = 1671.5000, C = 1671.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:43:00"), O = 1671.5000, H = 1671.7500, L = 1670.5000, C = 1671.0000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:44:00"), O = 1670.7500, H = 1671.7500, L = 1670.7500, C = 1671.7500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:45:00"), O = 1672.0000, H = 1672.2500, L = 1671.5000, C = 1671.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:46:00"), O = 1671.7500, H = 1671.7500, L = 1671.0000, C = 1671.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:47:00"), O = 1671.7500, H = 1672.2500, L = 1671.5000, C = 1671.7500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:48:00"), O = 1671.7500, H = 1672.7500, L = 1671.7500, C = 1672.5000 }, + new MinuteRec { QTime = TimeSpan.Parse("06:49:00"), O = 1672.2500, H = 1673.7500, L = 1672.2500, C = 1673.7500 }, + new MinuteRec { QTime = TimeSpan.Parse("06:50:00"), O = 1673.7500, H = 1675.0000, L = 1673.5000, C = 1675.0000 } + }; + + [Example("Minute data (TimeSpanAxis)")] + public static PlotModel MinuteData_TimeSpan() + { + var pm = new PlotModel { Title = "Minute Data (TimeSpanAxis)" }; + + var timeSpanAxis1 = new TimeSpanAxis { Position = AxisPosition.Bottom, StringFormat = "hh:mm" }; + pm.Axes.Add(timeSpanAxis1); + var linearAxis1 = new LinearAxis { Position = AxisPosition.Left }; + pm.Axes.Add(linearAxis1); + var candleStickSeries = new OldCandleStickSeries + { + CandleWidth = 5, + Color = OxyColors.DarkGray, + IncreasingFill = OxyColors.DarkGreen, + DecreasingFill = OxyColors.Red, + DataFieldX = "QTime", + DataFieldHigh = "H", + DataFieldLow = "L", + DataFieldOpen = "O", + DataFieldClose = "C", + TrackerFormatString = "High: {2:0.00}\nLow: {3:0.00}\nOpen: {4:0.00}\nClose: {5:0.00}", + ItemsSource = lst + }; + pm.Series.Add(candleStickSeries); + return pm; + } + + public class MinuteRec + { + public DateTime Time { get { return new DateTime(2013, 10, 8) + this.QTime; } } + public TimeSpan QTime { get; set; } + public double H { get; set; } + public double L { get; set; } + public double O { get; set; } + public double C { get; set; } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/FinancialSeries/VolumeSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/FinancialSeries/VolumeSeriesExamples.cs new file mode 100644 index 0000000..c1b978a --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FinancialSeries/VolumeSeriesExamples.cs @@ -0,0 +1,132 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("VolumeSeries")] + [Tags("Series")] + public static class VolumeSeriesExamples + { + [Example("Just Volume (combined), fixed axis")] + public static Example JustVolumeCombined_Fixed() + { + return CreateVolumeSeries("Just Volume (combined)", VolumeStyle.Combined, natural: false); + } + + [Example("Just Volume (combined), natural axis")] + public static Example JustVolumeCombined_Natural() + { + return CreateVolumeSeries("Just Volume (combined)", VolumeStyle.Combined, natural: true); + } + + [Example("Just Volume (stacked), fixed axis")] + public static Example JustVolumeStacked_Fixed() + { + return CreateVolumeSeries("Just Volume (stacked)", VolumeStyle.Stacked, natural: false); + } + + [Example("Just Volume (stacked), natural axis")] + public static Example JustVolumeStacked_Natural() + { + return CreateVolumeSeries("Just Volume (stacked)", VolumeStyle.Stacked, natural: true); + } + + [Example("Just Volume (+/-), fixed axis")] + public static Example JustVolumePositiveNegative_Fixed() + { + return CreateVolumeSeries("Just Volume (+/-)", VolumeStyle.PositiveNegative, natural: false); + } + + [Example("Just Volume (+/-), natural axis")] + public static Example JustVolumePositiveNegative_Natural() + { + return CreateVolumeSeries("Just Volume (+/-)", VolumeStyle.PositiveNegative, natural: true); + } + + /// + /// Creates the volume series. + /// + /// The volume series. + /// Title. + /// Style. + /// N. + /// If set to true natural. + /// If set to true transposed. + private static Example CreateVolumeSeries( + string title, + VolumeStyle style, + int n = 10000, + bool natural = false) + { + var pm = new PlotModel { Title = title }; + + var series = new VolumeSeries + { + PositiveColor = OxyColors.DarkGreen, + NegativeColor = OxyColors.Red, + PositiveHollow = false, + NegativeHollow = false, + VolumeStyle = style, + Title = "VolumeSeries", + }; + + // create bars + foreach (var bar in OhlcvItemGenerator.MRProcess(n)) + { + series.Append(bar); + } + + // create visible window + var Istart = n - 200; + var Iend = n - 120; + var Xmin = series.Items[Istart].X; + var Xmax = series.Items[Iend].X; + + // setup axes + var timeAxis = new DateTimeAxis + { + Position = AxisPosition.Bottom, + Minimum = Xmin, + Maximum = Xmax + }; + + var volAxis = new LinearAxis + { + Position = AxisPosition.Left, + StartPosition = 0.0, + EndPosition = 1.0, + Minimum = natural ? double.NaN : 0, + Maximum = natural ? double.NaN : 10000 + }; + + switch (style) + { + case VolumeStyle.Combined: + case VolumeStyle.Stacked: + pm.Axes.Add(timeAxis); + pm.Axes.Add(volAxis); + break; + + case VolumeStyle.PositiveNegative: + volAxis.Minimum = natural ? double.NaN : -10000; + pm.Axes.Add(timeAxis); + pm.Axes.Add(volAxis); + break; + } + + pm.Series.Add(series); + + var controller = new PlotController(); + controller.UnbindAll(); + controller.BindMouseDown(OxyMouseButton.Left, PlotCommands.PanAt); + return new Example(pm, controller); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/FunctionSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/FunctionSeriesExamples.cs new file mode 100644 index 0000000..8526514 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/FunctionSeriesExamples.cs @@ -0,0 +1,330 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("FunctionSeries"), Tags("Series")] + public class FunctionSeriesExamples + { + [Example("Square wave")] + public static PlotModel SquareWave() + { + return CreateSquareWave(25); + } + + private static PlotModel CreateSquareWave(int n = 25) + { + var plot = new PlotModel { Title = "Square wave (Gibbs phenomenon)" }; + + Func f = (x) => + { + double y = 0; + for (int i = 0; i < n; i++) + { + int j = i * 2 + 1; + y += Math.Sin(j * x) / j; + } + return y; + }; + + var fs = new FunctionSeries(f, -10, 10, 0.0001, "sin(x)+sin(3x)/3+sin(5x)/5+...+sin(" + (2 * n - 1) + ")/" + (2 * n - 1)); + + plot.Series.Add(fs); + plot.Subtitle = "n = " + fs.Points.Count; + + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + Minimum = -4, + Maximum = 4 + }); + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom + }); + + return plot; + } + + [Example("Parametric function 1")] + public static PlotModel Clover() + { + return CreateParametricPlot( + t => 2 * Math.Cos(2 * t) * Math.Cos(t), + t => 2 * Math.Cos(2 * t) * Math.Sin(t), + // t=>-4*Math.Sin(2*t)*Math.Cos(t)-2*Math.Cos(2*t)*Math.Sin(t), + // t=>-4*Math.Sin(2*t)*Math.Sin(t)+2*Math.Cos(2*t)*Math.Cos(t),)))) + 0, Math.PI * 2, 1000, + "Parametric function", + "Using the CartesianAxes property", + "2cos(2t)cos(t) , 2cos(2t)sin(t)"); + + } + + [Example("Parametric function 2")] + public static PlotModel ParametricFunction2() + { + return CreateParametricPlot( + t => 3 * Math.Sin(5 * t), + t => 3 * Math.Cos(3 * t), + 0, Math.PI * 2, 1000, + "Parametric function", + null, + "3sin(5t) , 3cos(3t)"); + } + + [Example("Parametric function 3")] + public static PlotModel ParametricFunction3() + { + return CreateParametricPlot( + t => 2 * Math.Cos(t) + Math.Cos(8 * t), + t => 2 * Math.Sin(t) + Math.Sin(8 * t), + 0, Math.PI * 2, 1000, + "Parametric function", + null, + "2cos(t)+cos(8t) , 2sin(t)+sin(8t)"); + } + + [Example("Lemniscate of Bernoulli")] + public static PlotModel LemniscateOfBernoulli() + { + // http://en.wikipedia.org/wiki/Lemniscate_of_Bernoulli + double a = 1; + return CreateParametricPlot( + t => a * Math.Sqrt(2) * Math.Cos(t) / (Math.Sin(t) * Math.Sin(t) + 1), + t => a * Math.Sqrt(2) * Math.Cos(t) * Math.Sin(t) / (Math.Sin(t) * Math.Sin(t) + 1), + 0, Math.PI * 2, 1000, "Lemniscate of Bernoulli"); + } + + [Example("Lemniscate of Gerono")] + public static PlotModel LemniscateOfGerono() + { + // http://en.wikipedia.org/wiki/Lemniscate_of_Gerono + return CreateParametricPlot(t => Math.Cos(t), t => Math.Sin(2 * t) / 2, 0, Math.PI * 2, 1000, "Lemniscate of Gerono"); + } + + [Example("Lissajous figure")] + public static PlotModel LissajousFigure() + { + double a = 3; + double b = 2; + double delta = Math.PI / 2; + // http://en.wikipedia.org/wiki/Lissajous_figure + return CreateParametricPlot(t => Math.Sin(a * t + delta), t => Math.Sin(b * t), 0, Math.PI * 2, 1000, "Lissajous figure", null, "a=3, b=2, δ = π/2"); + } + + [Example("Rose curve")] + public static PlotModel RoseCurve() + { + // http://en.wikipedia.org/wiki/Rose_curve + + var m = new PlotModel + { + Title = "Rose curve", + PlotType = PlotType.Polar, + PlotAreaBorderThickness = new OxyThickness(0) + }; + + m.Axes.Add(new AngleAxis + { + Minimum = 0, + Maximum = Math.PI * 2, + MajorStep = Math.PI / 4, + MinorStep = Math.PI / 16, + MajorGridlineStyle = LineStyle.Solid, + FormatAsFractions = true, + FractionUnit = Math.PI, + FractionUnitSymbol = "π" + }); + m.Axes.Add(new MagnitudeAxis() { MajorGridlineStyle = LineStyle.Solid }); + + int d = 4; + int n = 3; + double k = (double)n / d; + m.Series.Add(new FunctionSeries(t => Math.Sin(k * t), t => t, 0, Math.PI * 2 * d, 1000, string.Format("d={0}, n={1}", d, n))); + + return m; + } + + [Example("Limaçon of Pascal")] + [DocumentationExample("Series/FunctionSeries")] + public static PlotModel LimaconOfPascal() + { + // http://en.wikipedia.org/wiki/Lima%C3%A7on + + var m = new PlotModel { Title = "Limaçon of Pascal", PlotType = PlotType.Cartesian }; + for (int a = 4; a <= 4; a++) + for (int b = 0; b <= 10; b++) + { + m.Series.Add( + new FunctionSeries( + t => a / 2 + b * Math.Cos(t) + a / 2 * Math.Cos(2 * t), + t => b * Math.Sin(t) + a / 2 * Math.Sin(2 * t), + 0, + Math.PI * 2, + 1000, + string.Format("a={0}, b={1}", a, b))); + } + return m; + } + + [Example("Folium of Descartes")] + public static PlotModel DescartesFolium() + { + // http://www.wolframalpha.com/input/?i=folium+of+Descartes + + var m = new PlotModel { Title = "Folium of Descartes", PlotType = PlotType.Cartesian }; + m.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = -3, Maximum = 3 }); + m.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = -3, Maximum = 3 }); + double a = 1; + m.Series.Add(new FunctionSeries(t => 3 * a * t / (t * t * t + 1), t => 3 * a * t * t / (t * t * t + 1), -30, 30, 1001, string.Format("a={0}", a))); + + return m; + } + + [Example("Trisectrix of Maclaurin")] + public static PlotModel TrisectrixOfMaclaurin() + { + // http://en.wikipedia.org/wiki/Trisectrix_of_Maclaurin + // http://mathworld.wolfram.com/MaclaurinTrisectrix.html + + var m = new PlotModel { Title = "Trisectrix of Maclaurin", PlotType = PlotType.Cartesian }; + double a = 1; + m.Series.Add(new FunctionSeries(t => a * (t * t - 3) / (t * t + 1), t => a * t * (t * t - 3) / (t * t + 1), -5, 5, 1000)); + return m; + } + + [Example("Fermat's spiral")] + public static PlotModel FermatsSpiral() + { + // http://en.wikipedia.org/wiki/Fermat's_spiral + // http://www.wolframalpha.com/input/?i=Fermat%27s+spiral + var m = new PlotModel { Title = "Fermat's spiral", PlotType = PlotType.Cartesian }; + double a = 1; + m.Series.Add(new FunctionSeries(t => a * Math.Sqrt(t) * Math.Cos(t), t => a * Math.Sqrt(t) * Math.Sin(t), 0, 20, 1000)); + m.Series.Add(new FunctionSeries(t => -a * Math.Sqrt(t) * Math.Cos(t), t => -a * Math.Sqrt(t) * Math.Sin(t), 0, 20, 1000)); + return m; + } + + [Example("Fish curve")] + public static PlotModel FishCurve() + { + // http://www.wolframalpha.com/input/?i=fish+curve + var m = new PlotModel { Title = "Fish curve", PlotType = PlotType.Cartesian }; + for (double a = 0.1; a < 1; a += 0.1) + { + m.Series.Add(new FunctionSeries(t => a * (Math.Cos(t) - Math.Sin(t) * Math.Sin(t) / Math.Sqrt(2)), t => a * Math.Cos(t) * Math.Sin(t), 0, 2 * Math.PI, 1000)); + } + + return m; + } + + [Example("Heaviside step function")] + public static PlotModel HeavisideStepFunction() + { + // http://en.wikipedia.org/wiki/Heaviside_step_function + + var m = new PlotModel { Title = "Heaviside step function", PlotType = PlotType.Cartesian }; + m.Series.Add(new FunctionSeries(x => + { + // make a gap in the curve at x=0 + if (Math.Abs(x) < 1e-8) return double.NaN; + return x < 0 ? 0 : 1; + }, -2, 2, 0.001)); + m.Annotations.Add(new LineAnnotation { Type = LineAnnotationType.Vertical, Color = m.DefaultColors[0], X = 0, MinimumY = 0, MaximumY = 1 }); + return m; + } + + [Example("FunctionSeries")] + public static PlotModel FunctionSeries() + { + var pm = new PlotModel + { + Title = "Trigonometric functions", + Subtitle = "Example using the FunctionSeries", + PlotType = PlotType.Cartesian, + PlotAreaBackground = OxyColors.White + }; + pm.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.1, "sin(x)")); + pm.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.1, "cos(x)")); + pm.Series.Add(new FunctionSeries(t => 5 * Math.Cos(t), t => 5 * Math.Sin(t), 0, 2 * Math.PI, 1000, "cos(t),sin(t)")); + return pm; + } + + [Example("Squirqle")] + public static PlotModel Squirqle() + { + var plot = new PlotModel { Title = "Squirqle", PlotType = PlotType.Cartesian }; + plot.Series.Add(CreateSuperellipseSeries(4, 1, 1)); + + return plot; + } + + [Example("Superellipse n=20")] + public static PlotModel Superellipse20() + { + var plot = new PlotModel { Title = "Superellipse", PlotType = PlotType.Cartesian }; + var s = CreateSuperellipseSeries(20, 1, 1); + s.MarkerType = MarkerType.Circle; + plot.Series.Add(s); + + return plot; + } + + [Example("Lamé curves")] + public static PlotModel LameCurves() + { + var plot = new PlotModel { Title = "Lamé curves", PlotType = PlotType.Cartesian }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + plot.Legends.Add(l); + + for (double n = 0.25; n < 2; n += 0.25) + { + plot.Series.Add(CreateSuperellipseSeries(n, 1, 1)); + } + + for (double n = 2; n <= 8 + 1e-6; n += 1) + { + plot.Series.Add(CreateSuperellipseSeries(n, 1, 1)); + } + + return plot; + } + + public static FunctionSeries CreateSuperellipseSeries(double n, double a, double b) + { + // http://en.wikipedia.org/wiki/Superellipse + return new FunctionSeries( + t => a * Math.Sign(Math.Cos(t)) * Math.Pow(Math.Abs(Math.Cos(t)), 2 / n), + t => b * Math.Sign(Math.Sin(t)) * Math.Pow(Math.Abs(Math.Sin(t)), 2 / n), + 0, + Math.PI * 2, + 101, + string.Format("n={0}, a={1}, b={2}", n, a, b)); + } + + private static PlotModel CreateParametricPlot(Func fx, Func fy, double t0, + double t1, int n, string title, string subtitle = null, + string seriesTitle = null) + { + var plot = new PlotModel { Title = title, Subtitle = subtitle, PlotType = PlotType.Cartesian }; + plot.Series.Add(new FunctionSeries(fx, fy, t0, t1, n, seriesTitle)); + return plot; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/HeatMapSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/HeatMapSeriesExamples.cs new file mode 100644 index 0000000..fad590e --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/HeatMapSeriesExamples.cs @@ -0,0 +1,452 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Creates a simple example heat map from a 2×3 matrix. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("HeatMapSeries"), Tags("Series")] + public class HeatMapSeriesExamples + { + [Example("Peaks")] + [DocumentationExample("Series/HeatMapSeries")] + public static PlotModel Peaks() + { + return CreatePeaks(); + } + + public static PlotModel CreatePeaks(OxyPalette palette = null, bool includeContours = true, int n = 100) + { + double x0 = -3.1; + double x1 = 3.1; + double y0 = -3; + double y1 = 3; + Func peaks = (x, y) => 3 * (1 - x) * (1 - x) * Math.Exp(-(x * x) - (y + 1) * (y + 1)) - 10 * (x / 5 - x * x * x - y * y * y * y * y) * Math.Exp(-x * x - y * y) - 1.0 / 3 * Math.Exp(-(x + 1) * (x + 1) - y * y); + var xvalues = ArrayBuilder.CreateVector(x0, x1, n); + var yvalues = ArrayBuilder.CreateVector(y0, y1, n); + var peaksData = ArrayBuilder.Evaluate(peaks, xvalues, yvalues); + + var model = new PlotModel { Title = "Peaks" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = palette ?? OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + var hms = new HeatMapSeries { X0 = x0, X1 = x1, Y0 = y0, Y1 = y1, Data = peaksData }; + model.Series.Add(hms); + if (includeContours) + { + var cs = new ContourSeries + { + Color = OxyColors.Black, + FontSize = 0, + ContourLevelStep = 1, + LabelBackground = OxyColors.Undefined, + ColumnCoordinates = yvalues, + RowCoordinates = xvalues, + Data = peaksData + }; + model.Series.Add(cs); + } + + return model; + } + + [Example("2×3, interpolated")] + public static PlotModel Interpolated() + { + return CreateExample("Interpolated", true); + } + + [Example("2×3, interpolated, cartesian axes")] + public static PlotModel InterpolatedCartesian() + { + var model = CreateExample("Interpolated, cartesian axes", true); + model.PlotType = PlotType.Cartesian; + return model; + } + + [Example("2×3, interpolated with two NaN values")] + public static PlotModel InterpolatedWithNanValue() + { + var model = CreateExample("Interpolated including two NaN values", true); + var hms = (HeatMapSeries)model.Series[0]; + hms.Data[0, 1] = double.NaN; + hms.Data[1, 0] = double.NaN; + return model; + } + + [Example("2×3, interpolated with two NaN values, flat data")] + public static PlotModel InterpolatedWithNanValueFlat() + { + var model = CreateExample("Interpolated including two NaN values, otherwise 4.71", true); + var hms = (HeatMapSeries)model.Series[0]; + + double datum = 4.71d; + hms.Data[0, 0] = datum; + hms.Data[0, 1] = datum; + hms.Data[0, 2] = datum; + hms.Data[1, 0] = datum; + hms.Data[1, 1] = datum; + hms.Data[1, 2] = datum; + + hms.Data[0, 1] = double.NaN; + hms.Data[1, 0] = double.NaN; + return model; + } + + [Example("2×3, not interpolated")] + public static PlotModel NotInterpolated() + { + return CreateExample("Not interpolated values", false); + } + + [Example("2×3, not interpolated with two NaN values")] + public static PlotModel NotInterpolatedWithNanValue() + { + var model = CreateExample("Not interpolated values including two NaN values", false); + var ca = (LinearColorAxis)model.Axes[0]; + ca.InvalidNumberColor = OxyColors.Transparent; + var hms = (HeatMapSeries)model.Series[0]; + hms.Data[0, 1] = double.NaN; + hms.Data[1, 0] = double.NaN; + return model; + } + + [Example("2×3, not interpolated with two NaN values, flat data")] + public static PlotModel NotInterpolatedWithNanValueFlat() + { + var model = CreateExample("Not interpolated values including two NaN values, otherwise 4.71", false); + var ca = (LinearColorAxis)model.Axes[0]; + ca.InvalidNumberColor = OxyColors.Transparent; + var hms = (HeatMapSeries)model.Series[0]; + + double datum = 4.71d; + hms.Data[0, 0] = datum; + hms.Data[0, 1] = datum; + hms.Data[0, 2] = datum; + hms.Data[1, 0] = datum; + hms.Data[1, 1] = datum; + hms.Data[1, 2] = datum; + + hms.Data[0, 1] = double.NaN; + hms.Data[1, 0] = double.NaN; + return model; + } + + [Example("2×3, reversed x-axis")] + public static PlotModel NotInterpolatedReversedX() + { + var model = CreateExample("Reversed x-axis", false); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StartPosition = 1, EndPosition = 0 }); + return model; + } + + [Example("2×3, X0>X1")] + public static PlotModel X0GreaterThanX1() + { + var model = CreateExample("X0>X1", false); + var hms = (HeatMapSeries)model.Series[0]; + var tmp = hms.X0; + hms.X0 = hms.X1; + hms.X1 = tmp; + return model; + } + + [Example("2×3, reversed x-axis, X0>X1")] + public static PlotModel ReversedX_X0GreaterThanX1() + { + var model = CreateExample("Reversed x-axis, X0>X1", false); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StartPosition = 1, EndPosition = 0 }); + var hms = (HeatMapSeries)model.Series[0]; + var tmp = hms.X0; + hms.X0 = hms.X1; + hms.X1 = tmp; + return model; + } + + [Example("2×3, reversed y-axis")] + public static PlotModel NotInterpolatedReversedY() + { + var model = CreateExample("Reversed y-axis", false); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + return model; + } + + [Example("2×3, Y0>Y1")] + public static PlotModel Y0GreaterThanY1() + { + var model = CreateExample("Y0>Y1", false); + var hms = (HeatMapSeries)model.Series[0]; + var tmp = hms.Y0; + hms.Y0 = hms.Y1; + hms.Y1 = tmp; + return model; + } + + [Example("2×3, reversed y-axis, Y0>Y1")] + public static PlotModel ReversedY_Y0GreaterThanY1() + { + var model = CreateExample("Reversed y-axis, Y0>Y1", false); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + var hms = (HeatMapSeries)model.Series[0]; + var tmp = hms.Y0; + hms.Y0 = hms.Y1; + hms.Y1 = tmp; + return model; + } + + [Example("2x3, reversed x- and y-axis")] + public static PlotModel NotInterpolatedReversedXY() + { + var model = CreateExample("Reversed x- and y-axis", false); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StartPosition = 1, EndPosition = 0 }); + return model; + } + + [Example("3×3, diagonal (center defined)")] + public static PlotModel Diagonal() + { + var data = new double[3, 3]; + data[0, 0] = 1; + data[1, 1] = 1; + data[2, 2] = 1; + + var model = new PlotModel { Title = "Diagonal (center defined)" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + // adding half cellwidth/cellheight to bounding box coordinates + var hms = new HeatMapSeries { CoordinateDefinition = HeatMapCoordinateDefinition.Center, X0 = 0.5, X1 = 2.5, Y0 = 2.5, Y1 = 0.5, Data = data, Interpolate = false }; + model.Series.Add(hms); + return model; + } + + [Example("3×3, diagonal (edge defined)")] + public static PlotModel Diagonal2() + { + var data = new double[3, 3]; + data[0, 0] = 1; + data[1, 1] = 1; + data[2, 2] = 1; + + var model = new PlotModel { Title = "Diagonal (edge defined)" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + // adding half cellwidth/cellheight to bounding box coordinates + var hms = new HeatMapSeries { CoordinateDefinition = HeatMapCoordinateDefinition.Edge, X0 = 0, X1 = 3, Y0 = 3, Y1 = 0, Data = data, Interpolate = false }; + model.Series.Add(hms); + return model; + } + + [Example("6×6, diagonal")] + public static PlotModel Diagonal_6X6() + { + var data = new double[6, 6]; + data[0, 0] = 1; + data[1, 1] = 1; + data[2, 2] = 1; + data[3, 3] = 1; + data[4, 4] = 1; + data[5, 5] = 1; + + var model = new PlotModel { Title = "Diagonal 6×6" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + // note: the coordinates are specifying the centers of the edge cells + var hms = new HeatMapSeries { X0 = 0, X1 = 5, Y0 = 5, Y1 = 0, Data = data, Interpolate = false }; + model.Series.Add(hms); + return model; + } + + [Example("Confusion matrix")] + public static PlotModel ConfusionMatrix() + { + // Example provided by Pau Climent Pérez + // See also http://en.wikipedia.org/wiki/Confusion_matrix + var data = new double[3, 3]; + + data[0, 0] = 1; + data[1, 1] = 0.8; + data[1, 2] = 0.2; + data[2, 2] = 1; + + // I guess this is where the confusion comes from? + data = data.Transpose(); + + string[] cat1 = { "class A", "class B", "class C" }; + + var model = new PlotModel { Title = "Confusion Matrix" }; + + var palette = OxyPalette.Interpolate(50, OxyColors.White, OxyColors.Black); + + var lca = new LinearColorAxis { Position = AxisPosition.Right, Palette = palette, HighColor = OxyColors.White, LowColor = OxyColors.White }; + model.Axes.Add(lca); + + var axis1 = new CategoryAxis { Position = AxisPosition.Top, Title = "Actual class" }; + axis1.Labels.AddRange(cat1); + model.Axes.Add(axis1); + + // We invert this axis, so that they look "symmetrical" + var axis2 = new CategoryAxis { Position = AxisPosition.Left, Title = "Predicted class" }; + axis2.Labels.AddRange(cat1); + axis2.Angle = -90; + axis2.StartPosition = 1; + axis2.EndPosition = 0; + + model.Axes.Add(axis2); + + var hms = new HeatMapSeries + { + Data = data, + Interpolate = false, + LabelFontSize = 0.25, + X0 = 0, + X1 = data.GetLength(1) - 1, + Y0 = 0, + Y1 = data.GetLength(0) - 1, + }; + + model.Series.Add(hms); + return model; + } + + [Example("Logarithmic X, interpolated")] + public static PlotModel LogXInterpolated() + { + var data = new double[11, 21]; + + double k = Math.Pow(2, 0.1); + + for (int i = 0; i < 11; i++) + { + for (int j = 0; j < 21; j++) + { + data[i, j] = Math.Pow(k, (double)i) * (double)j / 40.0; + } + } + + var model = new PlotModel { Title = "Logarithmic X, interpolated" }; + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Gray(500), HighColor = OxyColors.White, LowColor = OxyColors.Black }); + + var hms = new HeatMapSeries { X0 = 1.0, X1 = 2.0, Y0 = 0, Y1 = 20, Data = data, Interpolate = true }; + + model.Series.Add(hms); + return model; + } + + [Example("Logarithmic X, discrete rectangles")] + public static PlotModel LogXNotInterpolated() + { + var data = new double[11, 21]; + + double k = Math.Pow(2, 0.1); + + for (int i = 0; i < 11; i++) + { + for (int j = 0; j < 21; j++) + { + data[i, j] = Math.Pow(k, (double)i) * (double)j / 40.0; + } + } + + var model = new PlotModel { Title = "Logarithmic X, discrete rectangles" }; + model.Axes.Add(new LogarithmicAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Gray(500), HighColor = OxyColors.White, LowColor = OxyColors.Black }); + + var hms = new HeatMapSeries { X0 = 1.0, X1 = 2.0, Y0 = 0, Y1 = 20, Data = data, Interpolate = false, RenderMethod = HeatMapRenderMethod.Rectangles, LabelFontSize = 0.4 }; + + model.Series.Add(hms); + return model; + } + + [Example("6×4, not transposed")] + public static PlotModel Normal_6X4() + { + return Create6X4("Normal 6×4 Heatmap"); + } + + private static PlotModel Create6X4(string title) + { + var data = new double[6, 4]; + + for (int i = 1; i <= 6; i++) + { + for (int j = 1; j <= 4; j++) + { + data[i - 1, j - 1] = i * j; + } + } + + var model = new PlotModel { Title = title, Subtitle = "Note the positions of the axes" }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.White, LowColor = OxyColors.Black }); + model.Series.Add(new HeatMapSeries { X0 = 1, X1 = 6, Y0 = 1, Y1 = 4, Data = data, Interpolate = true, LabelFontSize = 0.2 }); + return model; + } + + /// + /// Creates a simple example heat map from a 2×3 matrix. + /// + /// The title. + /// Interpolate the HeatMapSeries if set to true. + /// A . + private static PlotModel CreateExample(string title, bool interpolate) + { + var data = new double[2, 3]; + data[0, 0] = 0; + data[0, 1] = 0.2; + data[0, 2] = 0.4; + data[1, 0] = 0.1; + data[1, 1] = 0.3; + data[1, 2] = 0.2; + + var model = new PlotModel { Title = "HeatMapSeries", Subtitle = title }; + model.Axes.Add(new LinearColorAxis { Position = AxisPosition.Right, Palette = OxyPalettes.Jet(500), HighColor = OxyColors.Gray, LowColor = OxyColors.Black }); + + // adding half cellwidth/cellheight to bounding box coordinates + var hms = new HeatMapSeries + { + CoordinateDefinition = HeatMapCoordinateDefinition.Center, + X0 = 0.5, + X1 = 1.5, + Y0 = 0.5, + Y1 = 2.5, + Data = data, + Interpolate = interpolate, + LabelFontSize = 0.2, + }; + + model.Series.Add(hms); + return model; + } + } + + internal static class ArrayExtensions + { + public static double[,] Transpose(this double[,] input) + { + int m = input.GetLength(0); + int n = input.GetLength(1); + var output = new double[n, m]; + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + output[j, i] = input[i, j]; + } + } + + return output; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/HistogramSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/HistogramSeriesExamples.cs new file mode 100644 index 0000000..3a42873 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/HistogramSeriesExamples.cs @@ -0,0 +1,293 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Creates example histograms +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Linq; + + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using System.Collections.Generic; + + [Examples("HistogramSeries"), Tags("Series")] + public class HistogramSeriesExamples + { + [Example("Exponential Distribution")] + [DocumentationExample("Series/HistogramSeries")] + public static PlotModel ExponentialDistribution() + { + return CreateExponentialDistribution(); + } + + [Example("Exponential Distribution (logarithmic)")] + [DocumentationExample("Series/HistogramSeries")] + public static PlotModel ExponentialDistributionLogarithmicAxis() + { + return CreateExponentialDistribution(true); + } + + [Example("Exponential Distribution (logarithmic,with BaseValue)")] + [DocumentationExample("Series/HistogramSeries")] + public static PlotModel ExponentialDistributionLogarithmicAxisWithBaseValue() + { + return CreateExponentialDistribution(true, baseValue: 0.1); + } + + [Example("Label Placement")] + public static PlotModel HistogramLabelPlacement() + { + var model = new PlotModel { Title = "Label Placement" }; + + var s1 = new HistogramSeries { LabelPlacement = LabelPlacement.Base, LabelFormatString = "Base", StrokeThickness = 1, LabelMargin = 5 }; + var s2 = new HistogramSeries { LabelPlacement = LabelPlacement.Inside, LabelFormatString = "Inside", StrokeThickness = 1, LabelMargin = 5 }; + var s3 = new HistogramSeries { LabelPlacement = LabelPlacement.Middle, LabelFormatString = "Middle", StrokeThickness = 1, LabelMargin = 5 }; + var s4 = new HistogramSeries { LabelPlacement = LabelPlacement.Outside, LabelFormatString = "Outside", StrokeThickness = 1, LabelMargin = 5 }; + + s1.Items.Add(new HistogramItem(1, 2, 4, 4)); + s1.Items.Add(new HistogramItem(2, 3, -4, 4)); + s2.Items.Add(new HistogramItem(3, 4, 2, 2)); + s2.Items.Add(new HistogramItem(4, 5, -2, 2)); + s3.Items.Add(new HistogramItem(5, 6, 3, 3)); + s3.Items.Add(new HistogramItem(6, 7, -3, 3)); + s4.Items.Add(new HistogramItem(7, 8, 1, 1)); + s4.Items.Add(new HistogramItem(8, 9, -1, -1)); + + model.Series.Add(s1); + model.Series.Add(s2); + model.Series.Add(s3); + model.Series.Add(s4); + + return model; + } + + [Example("Label Placement (reversed Y Axis)")] + public static PlotModel LabelPlacementReversed() + { + return HistogramLabelPlacement().ReverseYAxis(); + } + + [Example("Label Format String")] + public static PlotModel LabelFormatString() + { + var model = CreateDisconnectedBins(); + var hs = model.Series[0] as HistogramSeries; + hs.LabelFormatString = "Start: {1:0.00}\nEnd: {2:0.00}\nValue: {0:0.00}\nArea: {3:0.00}\nCount: {4}"; + hs.LabelPlacement = LabelPlacement.Inside; + return model; + } + + [Example("Custom Bins")] + public static PlotModel CustomBins() + { + return CreateExponentialDistributionCustomBins(); + } + + [Example("Disconnected Bins")] + public static PlotModel DisconnectedBins() + { + return CreateDisconnectedBins(); + } + + [Example("Normal Distribution Three Colors")] + public static PlotModel NormalDistribution() + { + return CreateNormalDistribution(); + } + + [Example("Individual Bin Colors")] + public static PlotModel IndividualBinColors() + { + return CreateIndividualBinColors(); + } + + [Example("Custom Item Mapping")] + public static PlotModel CustomItemMapping() + { + var model = new PlotModel { Title = "Custom Item Mapping" }; + + var s = new HistogramSeries { Mapping = obj => (HistogramItem)obj, TrackerFormatString = "{Description}"}; + s.Items.Add(new CustomHistogramItem(1, 2, 4, 4, "Item 1")); + s.Items.Add(new CustomHistogramItem(2, 3, -4, 4, "Item 2")); + s.Items.Add(new CustomHistogramItem(3, 4, 2, 2, "Item 3")); + s.Items.Add(new CustomHistogramItem(4, 5, -2, 2, "Item 4")); + model.Series.Add(s); + + return model; + } + + public class CustomHistogramItem : HistogramItem + { + public CustomHistogramItem(double rangeStart, double rangeEnd, double area, int count, string description) + : base(rangeStart, rangeEnd, area, count) + { + this.Description = description; + } + + public string Description { get; } + } + + public static PlotModel CreateExponentialDistribution(bool logarithmicYAxis = false, double mean = 1, int n = 10000, double baseValue = 0) + { + var model = new PlotModel { Title = logarithmicYAxis ? "Exponential Distribution (logarithmic)" : "Exponential Distribution", Subtitle = "Uniformly distributed bins (" + n + " samples)" }; + model.Axes.Add( + logarithmicYAxis ? + (Axis)new LogarithmicAxis { Position = AxisPosition.Left, Title = "Frequency"} : + new LinearAxis { Position = AxisPosition.Left, Title = "Frequency" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "x" }); + + Random rnd = new Random(1); + + HistogramSeries chs = new HistogramSeries(); + + var binningOptions = new BinningOptions(BinningOutlierMode.CountOutliers, BinningIntervalType.InclusiveLowerBound, BinningExtremeValueMode.ExcludeExtremeValues); + var binBreaks = HistogramHelpers.CreateUniformBins(0, 5, 15); + chs.Items.AddRange(HistogramHelpers.Collect(SampleExps(rnd, mean, n), binBreaks, binningOptions)); + chs.StrokeThickness = 1; + chs.BaseValue = baseValue; + chs.NegativeFillColor = OxyColors.Red; + model.Series.Add(chs); + + return model; + } + + public static PlotModel CreateExponentialDistributionCustomBins(double mean = 1, int n = 50000) + { + var model = new PlotModel { Title = "Exponential Distribution", Subtitle = "Custom bins (" + n + " samples)" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Frequency" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "x" }); + + Random rnd = new Random(1); + + HistogramSeries chs = new HistogramSeries(); + + var binningOptions = new BinningOptions(BinningOutlierMode.CountOutliers, BinningIntervalType.InclusiveLowerBound, BinningExtremeValueMode.ExcludeExtremeValues); + chs.Items.AddRange(HistogramHelpers.Collect(SampleExps(rnd, mean, n), new double[] { 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0 }, binningOptions)); + chs.StrokeThickness = 1; + chs.FillColor = OxyColors.Purple; + model.Series.Add(chs); + + return model; + } + + public static PlotModel CreateNormalDistribution(double mean = 0, double std = 1, int n = 1000000) + { + var model = new PlotModel { Title = $"Normal Distribution (μ={mean}, σ={std})", Subtitle = "95% of the distribution (" + n + " samples)" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Frequency" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "x" }); + + Random rnd = new Random(1); + + HistogramSeries chs = new HistogramSeries(); + var binningOptions = new BinningOptions(BinningOutlierMode.CountOutliers, BinningIntervalType.InclusiveLowerBound, BinningExtremeValueMode.ExcludeExtremeValues); + var binBreaks = HistogramHelpers.CreateUniformBins(-std * 4, std * 4, 100); + chs.Items.AddRange(HistogramHelpers.Collect(SampleNormal(rnd, mean, std, n), binBreaks, binningOptions)); + chs.StrokeThickness = 1; + + double LimitHi = mean + 1.96 * std; + double LimitLo = mean - 1.96 * std; + OxyColor ColorHi = OxyColors.DarkRed; + OxyColor ColorLo = OxyColors.DarkRed; + + chs.ColorMapping = (item) => + { + if (item.RangeCenter > LimitHi) + { + return ColorHi; + } + else if (item.RangeCenter < LimitLo) + { + return ColorLo; + } + return chs.ActualFillColor; + }; + + model.Series.Add(chs); + + return model; + } + + public static PlotModel CreateDisconnectedBins() + { + var model = new PlotModel { Title = "Disconnected Bins" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Representation" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "x" }); + + HistogramSeries chs = new HistogramSeries(); + chs.Items.AddRange(new[] { new HistogramItem(0, 0.5, 10, 7), new HistogramItem(0.75, 1.0, 10, 7) }); + chs.LabelFormatString = "{0:0.00}"; + chs.LabelPlacement = LabelPlacement.Middle; + model.Series.Add(chs); + + return model; + } + + public static PlotModel CreateIndividualBinColors(double mean = 1, int n = 10000) + { + var model = new PlotModel { Title = "Individual Bin Colors", Subtitle = "Minimum is Red, Maximum is Green" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Frequency" }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Observation" }); + + Random rnd = new Random(1); + + HistogramSeries chs = new HistogramSeries() { FillColor = OxyColors.Gray, RenderInLegend = true, Title = "Measurements" }; + + var binningOptions = new BinningOptions(BinningOutlierMode.CountOutliers, BinningIntervalType.InclusiveLowerBound, BinningExtremeValueMode.ExcludeExtremeValues); + var binBreaks = HistogramHelpers.CreateUniformBins(0, 10, 20); + var bins = HistogramHelpers.Collect(SampleUniform(rnd, 0, 10, 1000), binBreaks, binningOptions).OrderBy(b => b.Count).ToArray(); + bins.First().Color = OxyColors.Red; + bins.Last().Color = OxyColors.Green; + chs.Items.AddRange(bins); + chs.StrokeThickness = 1; + model.Series.Add(chs); + + return model; + } + + private static IEnumerable SampleExps(Random rnd, double mean, int count) + { + for (int i = 0; i < count; i++) + { + yield return SampleExp(rnd, mean); + } + } + + private static double SampleExp(Random rnd, double mean) + { + return Math.Log(1.0 - rnd.NextDouble()) / -mean; + } + + private static IEnumerable SampleNormal(Random rnd, double mean, double std, int count) + { + for (int i = 0; i < count; i++) + { + yield return SampleNormal(rnd, mean, std); + } + } + + private static double SampleNormal(Random rnd, double mean, double std) + { + // http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + var u1 = 1.0 - rnd.NextDouble(); + var u2 = rnd.NextDouble(); + return Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2) * std + mean; + } + + private static IEnumerable SampleUniform(Random rnd, double min, double max, int count) + { + for (int i = 0; i < count; i++) + { + yield return rnd.NextDouble() * (max - min) + min; + } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/IntervalBarSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/IntervalBarSeriesExamples.cs new file mode 100644 index 0000000..e437eaf --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/IntervalBarSeriesExamples.cs @@ -0,0 +1,119 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("IntervalBarSeries"), Tags("Series")] + public static class IntervalBarSeriesExamples + { + [Example("IntervalBarSeries")] + [DocumentationExample("Series/IntervalBarSeries")] + public static PlotModel IntervalBarSeries() + { + var model = new PlotModel { Title = "IntervalBarSeries" }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + + var s1 = new IntervalBarSeries { Title = "IntervalBarSeries 1", LabelFormatString = "{0} - {1}"}; + s1.Items.Add(new IntervalBarItem { Start = 6, End = 8 }); + s1.Items.Add(new IntervalBarItem { Start = 4, End = 8 }); + s1.Items.Add(new IntervalBarItem { Start = 5, End = 11 }); + s1.Items.Add(new IntervalBarItem { Start = 4, End = 12 }); + model.Series.Add(s1); + var s2 = new IntervalBarSeries { Title = "IntervalBarSeries 2", LabelFormatString = "{0} - {1}" }; + s2.Items.Add(new IntervalBarItem { Start = 8, End = 9 }); + s2.Items.Add(new IntervalBarItem { Start = 8, End = 10 }); + s2.Items.Add(new IntervalBarItem { Start = 11, End = 12 }); + s2.Items.Add(new IntervalBarItem { Start = 12, End = 12.5 }); + model.Series.Add(s2); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("Activity A"); + categoryAxis.Labels.Add("Activity B"); + categoryAxis.Labels.Add("Activity C"); + categoryAxis.Labels.Add("Activity D"); + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0.1, MaximumPadding = 0.1 }; + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + [Example("IntervalBarSeries with various label types")] + public static PlotModel IntervalBarSeriesWithLabels() + { + var model = new PlotModel { Title = "IntervalBarSeries" }; + var l = new Legend { LegendPlacement = LegendPlacement.Outside }; + + model.Legends.Add(l); + + var s1 = new IntervalBarSeries { Title = "IntervalBarSeries 1", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Outside }; + s1.Items.Add(new IntervalBarItem { Start = 6, End = 8, CategoryIndex = 0 }); + s1.Items.Add(new IntervalBarItem { Start = 10, End = 12, CategoryIndex = 0 }); + model.Series.Add(s1); + + var s2 = new IntervalBarSeries { Title = "IntervalBarSeries 2", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Inside }; + s2.Items.Add(new IntervalBarItem { Start = 4, End = 8, CategoryIndex = 1 }); + s2.Items.Add(new IntervalBarItem { Start = 10, End = 12, CategoryIndex = 1 }); + model.Series.Add(s2); + + var s3 = new IntervalBarSeries { Title = "IntervalBarSeries 3", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Middle }; + s3.Items.Add(new IntervalBarItem { Start = 5, End = 11, CategoryIndex = 2 }); + s3.Items.Add(new IntervalBarItem { Start = 13, End = 17, CategoryIndex = 2 }); + model.Series.Add(s3); + + var s4 = new IntervalBarSeries { Title = "IntervalBarSeries 4", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Base }; + s4.Items.Add(new IntervalBarItem { Start = 4, End = 12, CategoryIndex = 3 }); + s4.Items.Add(new IntervalBarItem { Start = 13, End = 17, CategoryIndex = 3 }); + model.Series.Add(s4); + + var s5 = new IntervalBarSeries { Title = "IntervalBarSeries 5", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Outside, LabelAngle = -45 }; + s5.Items.Add(new IntervalBarItem { Start = 6, End = 8, CategoryIndex = 4 }); + s5.Items.Add(new IntervalBarItem { Start = 10, End = 12, CategoryIndex = 4 }); + model.Series.Add(s5); + + var s6 = new IntervalBarSeries { Title = "IntervalBarSeries 6", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Inside, LabelAngle = -45 }; + s6.Items.Add(new IntervalBarItem { Start = 4, End = 8, CategoryIndex = 5 }); + s6.Items.Add(new IntervalBarItem { Start = 10, End = 12, CategoryIndex = 5 }); + model.Series.Add(s6); + + var s7 = new IntervalBarSeries { Title = "IntervalBarSeries 7", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Middle, LabelAngle = -45 }; + s7.Items.Add(new IntervalBarItem { Start = 5, End = 11, CategoryIndex = 6 }); + s7.Items.Add(new IntervalBarItem { Start = 13, End = 17, CategoryIndex = 6 }); + model.Series.Add(s7); + + var s8 = new IntervalBarSeries { Title = "IntervalBarSeries 8", LabelFormatString = "{0} - {1}", LabelPlacement = LabelPlacement.Base, LabelAngle = -45 }; + s8.Items.Add(new IntervalBarItem { Start = 4, End = 12, CategoryIndex = 7 }); + s8.Items.Add(new IntervalBarItem { Start = 13, End = 17, CategoryIndex = 7 }); + model.Series.Add(s8); + + var categoryAxis = new CategoryAxis { Key = "CategoryAxis", Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }; + categoryAxis.Labels.Add("Label Outside"); + categoryAxis.Labels.Add("Label Inside"); + categoryAxis.Labels.Add("Label Middle"); + categoryAxis.Labels.Add("Label Base"); + categoryAxis.Labels.Add("Label Outside (angled)"); + categoryAxis.Labels.Add("Label Inside (angled)"); + categoryAxis.Labels.Add("Label Middle (angled)"); + categoryAxis.Labels.Add("Label Base (angled)"); + + var valueAxis = new LinearAxis { Key = "ValueAxis", Position = AxisPosition.Bottom, MinimumPadding = 0.1, MaximumPadding = 0.1 }; + + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/LineSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/LineSeriesExamples.cs new file mode 100644 index 0000000..9de5be2 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/LineSeriesExamples.cs @@ -0,0 +1,503 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("LineSeries"), Tags("Series")] + public class LineSeriesExamples + { + private static readonly Random Randomizer = new Random(13); + + [Example("Default style")] + [DocumentationExample("Series/LineSeries")] + public static PlotModel DefaultStyle() + { + var model = new PlotModel { Title = "LineSeries with default style" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var lineSeries1 = CreateExampleLineSeries(); + lineSeries1.Title = "LineSeries 1"; + model.Series.Add(lineSeries1); + + return model; + } + + [Example("Custom style")] + public static PlotModel CustomStyle() + { + var model = new PlotModel { Title = "LineSeries with custom style" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var lineSeries1 = CreateExampleLineSeries(); + lineSeries1.Title = "LineSeries 1"; + lineSeries1.ToolTip = "This is a tooltip for a LineSeries 1"; + lineSeries1.Color = OxyColors.SkyBlue; + lineSeries1.StrokeThickness = 3; + lineSeries1.LineStyle = LineStyle.Dash; + lineSeries1.MarkerType = MarkerType.Circle; + lineSeries1.MarkerSize = 5; + lineSeries1.MarkerStroke = OxyColors.White; + lineSeries1.MarkerFill = OxyColors.SkyBlue; + lineSeries1.MarkerStrokeThickness = 1.5; + model.Series.Add(lineSeries1); + + return model; + } + + [Example("Two LineSeries")] + public static PlotModel TwoLineSeries() + { + var model = new PlotModel { Title = "Two LineSeries" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var lineSeries1 = CreateExampleLineSeries(); + lineSeries1.Title = "LineSeries 1"; + model.Series.Add(lineSeries1); + + var lineSeries2 = CreateExampleLineSeries(41); + lineSeries2.Title = "LineSeries 2"; + model.Series.Add(lineSeries2); + return model; + } + + [Example("Visibility")] + public static PlotModel IsVisibleFalse() + { + var model = new PlotModel { Title = "LineSeries with IsVisible = false", Subtitle = "Click to change the IsVisible property for LineSeries 2" }; + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Minimum = 0, Maximum = 50 }); + + var s1 = CreateExampleLineSeries(38); + s1.Title = "LineSeries 1"; + model.Series.Add(s1); + + var s2 = CreateExampleLineSeries(39); + s2.Title = "LineSeries 2"; + s2.IsVisible = false; + model.Series.Add(s2); + + // handle mouse clicks to change visibility + model.MouseDown += (s, e) => { s2.IsVisible = !s2.IsVisible; model.InvalidatePlot(true); }; + + return model; + } + + [Example("Custom TrackerFormatString")] + public static PlotModel TrackerFormatString() + { + var model = new PlotModel { Title = "LineSeries with custom TrackerFormatString", Subtitle = "TrackerFormatString = \"X={2:0.0} Y={4:0.0}\"" }; + + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + + var lineSeries1 = CreateExampleLineSeries(); + lineSeries1.TrackerFormatString = "X={2:0.0} Y={4:0.0}"; + model.Series.Add(lineSeries1); + return model; + } + + [Example("Custom markers")] + public static PlotModel CustomMarkers() + { + var model = new PlotModel { Title = "LineSeries with custom markers" }; + var l = new Legend + { + LegendSymbolLength = 30 + }; + + model.Legends.Add(l); + const int N = 6; + var customMarkerOutline = new ScreenPoint[N]; + for (int i = 0; i < N; i++) + { + double th = Math.PI * ((4.0 * i / (N - 1)) - 0.5); + const double R = 1; + customMarkerOutline[i] = new ScreenPoint(Math.Cos(th) * R, Math.Sin(th) * R); + } + + var s1 = CreateExampleLineSeries(39); + s1.Title = "LineSeries 1"; + s1.MarkerType = MarkerType.Custom; + s1.MarkerSize = 8; + s1.MarkerOutline = customMarkerOutline; + + model.Series.Add(s1); + + return model; + } + + [Example("Marker types")] + public static PlotModel MarkerTypes() + { + var pm = CreateModel("LineSeries with different MarkerType", (int)MarkerType.Custom); + + var l = new Legend + { + LegendBackground = OxyColor.FromAColor(220, OxyColors.White), + LegendBorder = OxyColors.Black, + LegendBorderThickness = 1.0 + }; + + pm.Legends.Add(l); + + int i = 0; + foreach (var ls in pm.Series.Cast()) + { + ls.Color = OxyColors.Red; + ls.MarkerStroke = OxyColors.Black; + ls.MarkerFill = OxyColors.Green; + ls.MarkerType = (MarkerType)i++; + ls.Title = ls.MarkerType.ToString(); + } + + return pm; + } + + [Example("Labels")] + public static PlotModel Labels() + { + var model = new PlotModel { Title = "LineSeries with labels", Subtitle = "Use the 'LabelFormatString' property" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MaximumPadding = 0.1 }); // increase the top padding to make sure the labels are visible + var s1 = CreateExampleLineSeries(); + s1.LabelFormatString = "{1}"; + s1.MarkerType = MarkerType.Circle; + model.Series.Add(s1); + return model; + } + + [Example("LineStyle")] + public static PlotModel LineStyles() + { + var pm = CreateModel("LineSeries with LineStyle", (int)LineStyle.None); + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendSymbolLength = 50 + }; + + pm.Legends.Add(l); + + int i = 0; + foreach (var lineSeries in pm.Series.Cast()) + { + lineSeries.Color = OxyColors.Red; + lineSeries.LineStyle = (LineStyle)i++; + lineSeries.Title = lineSeries.LineStyle.ToString(); + } + + return pm; + } + + [Example("Interpolation")] + public static PlotModel Smooth() + { + var model = new PlotModel { Title = "LineSeries with interpolation", Subtitle = "InterpolationAlgorithm = CanonicalSpline" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + var s1 = CreateExampleLineSeries(); + s1.MarkerType = MarkerType.Circle; + s1.InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline; + model.Series.Add(s1); + + return model; + } + + [Example("LineLegendPosition")] + public static PlotModel CustomLineLegendPosition() + { + var model = new PlotModel { Title = "LineSeries with LineLegendPosition" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MinimumPadding = 0.05, MaximumPadding = 0.05 }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MinimumPadding = 0.05, MaximumPadding = 0.05 }); + var s1 = CreateExampleLineSeries(); + s1.Title = "Start"; + s1.MarkerType = MarkerType.Circle; + s1.LineLegendPosition = LineLegendPosition.Start; + model.Series.Add(s1); + + var s2 = CreateExampleLineSeries(41); + s2.Title = "End"; + s2.MarkerType = MarkerType.Circle; + s2.LineLegendPosition = LineLegendPosition.End; + model.Series.Add(s2); + + return model; + } + + [Example("LineLegendPosition (reversed X Axis)")] + public static PlotModel CustomLineLegendPositionReversed() + { + return CustomLineLegendPosition().ReverseXAxis(); + } + + [Example("Broken lines")] + public static PlotModel BrokenLine() + { + var model = new PlotModel { Title = "LineSeries with broken lines" }; + + var s1 = CreateExampleLineSeries(); + s1.Points[3] = DataPoint.Undefined; + s1.Points[7] = DataPoint.Undefined; + s1.BrokenLineColor = OxyColors.Gray; + s1.BrokenLineThickness = 0.5; + s1.BrokenLineStyle = LineStyle.Solid; + model.Series.Add(s1); + + var s2 = CreateExampleLineSeries(49); + s2.Points[3] = DataPoint.Undefined; + s2.Points[7] = DataPoint.Undefined; + s2.BrokenLineColor = OxyColors.Automatic; + s2.BrokenLineThickness = 1; + s2.BrokenLineStyle = LineStyle.Dot; + model.Series.Add(s2); + + return model; + } + + [Example("Without Decimator")] + public static PlotModel WithoutDecimator() + { + var model = new PlotModel { Title = "LineSeries without Decimator" }; + var s1 = CreateSeriesSuitableForDecimation(); + model.Series.Add(s1); + return model; + } + + [Example("With X Decimator")] + public static PlotModel WithXDecimator() + { + var model = new PlotModel { Title = "LineSeries with X Decimator" }; + var s1 = CreateSeriesSuitableForDecimation(); + s1.Decimator = Decimator.Decimate; + model.Series.Add(s1); + return model; + } + + [Example("Canonical spline interpolation")] + public static PlotModel CanonicalSplineInterpolation() + { + var result = CreateRandomPoints(); + + var plotModel = new PlotModel + { + Title = "Canonical spline interpolation", + Series = + { + new LineSeries + { + ItemsSource = result, + Title = "Default (0.5)", + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + MarkerType = MarkerType.Circle, + MarkerFill = OxyColors.Black + }, + new LineSeries + { + ItemsSource = result, + Title = "0.1", + InterpolationAlgorithm = new CanonicalSpline(0.1) + }, + new LineSeries + { + ItemsSource = result, + Title = "1.0", + InterpolationAlgorithm = new CanonicalSpline(1) + } + } + }; + + return plotModel; + } + + [Example("Catmull-Rom interpolation")] + public static PlotModel CatmullRomInterpolation() + { + var result = CreateRandomPoints(); + + var plotModel = new PlotModel + { + Title = "Catmull-Rom interpolation", + Series = + { + new LineSeries + { + ItemsSource = result, + Title = "Standard", + InterpolationAlgorithm = InterpolationAlgorithms.CatmullRomSpline, + MarkerType = MarkerType.Circle, + MarkerFill = OxyColors.Black + }, + new LineSeries + { + ItemsSource = result, + Title = "Chordal", + InterpolationAlgorithm = InterpolationAlgorithms.ChordalCatmullRomSpline + }, + new LineSeries + { + ItemsSource = result, + Title = "Uniform", + InterpolationAlgorithm = InterpolationAlgorithms.UniformCatmullRomSpline + } + } + }; + + return plotModel; + } + + [Example("Marker color options")] + public static PlotModel MarkerColorOptions() + { + var result = CreateRandomPoints(); + + var model = new PlotModel { Title = "Marker color options" }; + + // Dont specify line or marker color. Defaults will be used. + var s1 = CreateExampleLineSeries(1); + s1.MarkerType = MarkerType.Circle; + model.Series.Add(s1); + + // Specify line color but not marker color. Marker color should be the same as line color. + var s2 = CreateExampleLineSeries(4); + s2.MarkerType = MarkerType.Square; + s2.Color = OxyColors.LightBlue; + model.Series.Add(s2); + + // Specify marker color but not line color. Default color should be used for line. + var s3 = CreateExampleLineSeries(13); + s3.MarkerType = MarkerType.Square; + s3.MarkerFill = OxyColors.Black; + model.Series.Add(s3); + + // Specify line and marker color. Specified colors should be used. + var s4 = CreateExampleLineSeries(5); + s4.MarkerType = MarkerType.Square; + s4.MarkerFill = OxyColors.OrangeRed; + s4.Color = OxyColors.Orange; + model.Series.Add(s4); + + return model; + } + + private static List CreateRandomPoints(int numberOfPoints = 50) + { + var r = new Random(13); + var result = new List(numberOfPoints); + for (int i = 0; i < numberOfPoints; i++) + { + if (i < 5) + { + result.Add(new DataPoint(i, 0.0)); + } + else if (i < 10) + { + result.Add(new DataPoint(i, 1.0)); + } + else if (i < 12) + { + result.Add(new DataPoint(i, 0.0)); + } + else + { + result.Add(new DataPoint(i, r.NextDouble())); + } + } + return result; + } + + /// + /// Creates an example line series. + /// + /// A line series containing random points. + private static LineSeries CreateExampleLineSeries(int seed = 13) + { + var lineSeries1 = new LineSeries(); + var r = new Random(seed); + var y = r.Next(10, 30); + for (int x = 0; x <= 100; x += 10) + { + lineSeries1.Points.Add(new DataPoint(x, y)); + y += r.Next(-5, 5); + } + + return lineSeries1; + } + + private static PlotModel CreateModel(string title, int n = 20) + { + var model = new PlotModel { Title = title }; + for (int i = 1; i <= n; i++) + { + var s = new LineSeries { Title = "Series " + i }; + model.Series.Add(s); + for (double x = 0; x < 2 * Math.PI; x += 0.1) + { + s.Points.Add(new DataPoint(x, (Math.Sin(x * i) / (i + 1)) + i)); + } + } + + return model; + } + + private static LineSeries CreateSeriesSuitableForDecimation() + { + var s1 = new LineSeries(); + + int n = 20000; + for (int i = 0; i < n; i++) + { + s1.Points.Add(new DataPoint((double)i / n, Math.Sin(i))); + } + + return s1; + } + + private static OxyPlot.Series.Series CreateRandomLineSeries(int n, string title, MarkerType markerType) + { + var s1 = new LineSeries { Title = title, MarkerType = markerType, MarkerStroke = OxyColors.Black, MarkerStrokeThickness = 1.0 }; + double x = 0; + double y = 0; + for (int i = 0; i < n; i++) + { + x += 2 + Randomizer.NextDouble() * 10; + y += 1 + Randomizer.NextDouble(); + var p = new DataPoint(x, y); + s1.Points.Add(p); + } + + return s1; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/LinearBarSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/LinearBarSeriesExamples.cs new file mode 100644 index 0000000..31130cc --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/LinearBarSeriesExamples.cs @@ -0,0 +1,119 @@ +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("LinearBarSeries"), Tags("Series")] + public class LinearBarSeriesExamples + { + //private static readonly Random Randomizer = new Random(13); + + [Example("Default style")] + [DocumentationExample("Series/LinearBarSeries")] + public static PlotModel DefaultStyle() + { + var model = new PlotModel { Title = "LinearBarSeries with default style" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var linearBarSeries = CreateExampleLinearBarSeries(); + linearBarSeries.Title = "LinearBarSeries"; + model.Series.Add(linearBarSeries); + + return model; + } + + [Example("With stroke")] + public static PlotModel WithStroke() + { + var model = new PlotModel { Title = "LinearBarSeries with stroke" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + var linearBarSeries = CreateExampleLinearBarSeries(); + linearBarSeries.Title = "LinearBarSeries"; + linearBarSeries.FillColor = OxyColor.Parse("#454CAF50"); + linearBarSeries.StrokeColor = OxyColor.Parse("#4CAF50"); + linearBarSeries.StrokeThickness = 1; + model.Series.Add(linearBarSeries); + + return model; + } + + [Example("With negative colors")] + public static PlotModel WithNegativeColors() + { + return CreateWithNegativeColors(); + } + + [Example("With negative colors (logaritmic)")] + public static PlotModel WithNegativeColorsLogarithmic() + { + return CreateWithNegativeColors(logarithmic: true); + } + + [Example("With BaseValue")] + public static PlotModel WithBaseValue() + { + return CreateWithNegativeColors(baseValue: 50); + } + + [Example("With BaseValue (Logarithmic)")] + public static PlotModel WithBaseValueLogarithmic() + { + return CreateWithNegativeColors(logarithmic: true, baseValue: 50); + } + + public static PlotModel CreateWithNegativeColors(bool logarithmic = false, double baseValue = 0) + { + var model = new PlotModel { Title = logarithmic ? "LinearBarSeries with stroke (logarithmic)" : "LinearBarSeries with stroke" }; + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Axes.Add(logarithmic ? (Axis)new LogarithmicAxis { Position = AxisPosition.Left } : new LinearAxis { Position = AxisPosition.Left }); + var linearBarSeries = CreateExampleLinearBarSeriesWithNegativeValues(); + linearBarSeries.Title = "LinearBarSeries"; + linearBarSeries.FillColor = OxyColor.Parse("#454CAF50"); + linearBarSeries.StrokeColor = OxyColor.Parse("#4CAF50"); + linearBarSeries.NegativeFillColor = OxyColor.Parse("#45BF360C"); + linearBarSeries.NegativeStrokeColor = OxyColor.Parse("#BF360C"); + linearBarSeries.StrokeThickness = 1; + linearBarSeries.BaseValue = baseValue; + model.Series.Add(linearBarSeries); + + return model; + } + + /// + /// Creates an example linear bar series. + /// + /// A linear bar series containing random points. + private static LinearBarSeries CreateExampleLinearBarSeries() + { + var linearBarSeries = new LinearBarSeries(); + var r = new Random(31); + var y = r.Next(10, 30); + for (int x = 0; x <= 50; x++) + { + linearBarSeries.Points.Add(new DataPoint(x, y)); + y += r.Next(-5, 5); + } + return linearBarSeries; + } + + /// + /// Creates an example linear bar series with negative values. + /// + /// A linear bar series containing random points. + private static LinearBarSeries CreateExampleLinearBarSeriesWithNegativeValues() + { + var linearBarSeries = new LinearBarSeries(); + var r = new Random(31); + for (int x = 0; x <= 50; x++) + { + var y = -200 + r.Next(1000); + linearBarSeries.Points.Add(new DataPoint(x, y)); + } + return linearBarSeries; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/PieSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/PieSeriesExamples.cs new file mode 100644 index 0000000..387bfe1 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/PieSeriesExamples.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Series; + + [Examples("PieSeries"), Tags("Series")] + public static class PieSeriesExamples + { + [Example("PieSeries")] + [DocumentationExample("Series/PieSeries")] + public static PlotModel PieSeries() + { + return CreateExample(); + } + + [Example("PieSeries with inside label color")] + public static PlotModel InsideLabelColor() + { + var model = CreateExample(); + var series = (PieSeries)model.Series[0]; + series.InsideLabelColor = OxyColors.White; + return model; + } + + private static PlotModel CreateExample() + { + var model = new PlotModel { Title = "World population by continent" }; + + var ps = new PieSeries + { + StrokeThickness = 2.0, + InsideLabelPosition = 0.8, + AngleSpan = 360, + StartAngle = 0 + }; + + // http://www.nationsonline.org/oneworld/world_population.htm + // http://en.wikipedia.org/wiki/Continent + ps.Slices.Add(new PieSlice("Africa", 1030) { IsExploded = true }); + ps.Slices.Add(new PieSlice("Americas", 929) { IsExploded = true }); + ps.Slices.Add(new PieSlice("Asia", 4157)); + ps.Slices.Add(new PieSlice("Europe", 739) { IsExploded = true }); + ps.Slices.Add(new PieSlice("Oceania", 35) { IsExploded = true }); + + model.Series.Add(ps); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/RectangleBarSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/RectangleBarSeriesExamples.cs new file mode 100644 index 0000000..b47c5fd --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/RectangleBarSeriesExamples.cs @@ -0,0 +1,40 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("RectangleBarSeries"), Tags("Series")] + public static class RectangleBarSeriesExamples + { + [Example("RectangleBarSeries")] + [DocumentationExample("Series/RectangleBarSeries")] + public static PlotModel RectangleBarSeries() + { + var model = new PlotModel { Title = "RectangleBarSeries" }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + var s1 = new RectangleBarSeries { Title = "RectangleBarSeries 1" }; + s1.Items.Add(new RectangleBarItem { X0 = 2, X1 = 8, Y0 = 1, Y1 = 4 }); + s1.Items.Add(new RectangleBarItem { X0 = 6, X1 = 12, Y0 = 6, Y1 = 7 }); + model.Series.Add(s1); + + var s2 = new RectangleBarSeries { Title = "RectangleBarSeries 2" }; + s2.Items.Add(new RectangleBarItem { X0 = 2, X1 = 8, Y0 = -4, Y1 = -1 }); + s2.Items.Add(new RectangleBarItem { X0 = 6, X1 = 12, Y0 = -7, Y1 = -6 }); + model.Series.Add(s2); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/RectangleSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/RectangleSeriesExamples.cs new file mode 100644 index 0000000..b12384e --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/RectangleSeriesExamples.cs @@ -0,0 +1,77 @@ +namespace ExampleLibrary +{ + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("RectangleSeries"), Tags("Series")] + public static class RectangleSeriesExamples + { + [Example("RectangleSeries")] + [DocumentationExample("Series/RectangleSeries")] + public static PlotModel FromItems() + { + const int NumberOfItems = 10; + var model = new PlotModel { Title = "RectangleSeries" }; + + // the RectangleSeries requires a color axis + model.Axes.Add(new LinearColorAxis + { + Position = AxisPosition.Right, + Palette = OxyPalettes.Jet(100) + }); + + // create the series and add some rectangles with values + var s = new RectangleSeries() { LabelFontSize = 12 }; + for (int i = NumberOfItems - 1; i >= 0; i--) + { + s.Items.Add(new RectangleItem(-i * 0.5, i * 0.5, i * i, i * (i + 3), i)); + } + + model.Series.Add(s); + + return model; + } + + [Example("RectangleSeries from ItemsSource and Mapping")] + public static PlotModel FromItemsSource() + { + const int NumberOfItems = 10; + var model = new PlotModel { Title = "RectangleSeries" }; + + // the RectangleSeries requires a color axis + model.Axes.Add(new LinearColorAxis + { + Position = AxisPosition.Right, + Palette = OxyPalettes.Jet(100) + }); + + // create the data + var items = new List(); + for (int i = 0; i < NumberOfItems; i++) + { + items.Add(new MyItem { X = i, Value = i }); + } + + model.Series.Add(new RectangleSeries + { + ItemsSource = items, + Mapping = x => + { + var r = (MyItem)x; + return new RectangleItem(r.X, r.X * 2, r.X, r.X * 2, r.Value); + } + }); + + return model; + } + + public class MyItem + { + public double X { get; set; } + public double Value { get; set; } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/ScatterErrorSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/ScatterErrorSeriesExamples.cs new file mode 100644 index 0000000..9e6a92a --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/ScatterErrorSeriesExamples.cs @@ -0,0 +1,199 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Creates an example model with the specified number of points. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("ScatterErrorSeries"), Tags("Series")] + public class ScatterErrorSeriesExamples + { + [Example("Random points and errors (n=20)")] + [DocumentationExample("Series/ScatterErrorSeries")] + public static PlotModel RandomPointsAndError20() + { + return RandomPointsAndError(20); + } + + [Example("Random points and errors (n=2000)")] + public static PlotModel RandomPointsAndError2000() + { + return RandomPointsAndError(2000); + } + + [Example("Definining points by ItemsSource and Mapping")] + public static PlotModel ItemsSourceMapping() + { + const int N = 20; + var model = new PlotModel { Title = "ScatterErrorSeries, points defined by ItemsSource and Mapping", Subtitle = string.Format("Random data (n={0})", N) }; + var l = new Legend + { + LegendPosition = LegendPosition.LeftTop + }; + + model.Legends.Add(l); + model.Series.Add(new ScatterErrorSeries + { + Title = "Measurements", + ItemsSource = CreateExamplePoints(N).ToArray(), + Mapping = + obj => + { + var p = (ExamplePoint)obj; + return new ScatterErrorPoint(p.V1, p.V2, p.E1, p.E2); + } + }); + return model; + } + + [Example("Defining points by ItemsSource (List)")] + public static PlotModel ItemsSourceList() + { + const int N = 20; + var model = new PlotModel { Title = "ScatterErrorSeries, points defined by ItemsSource (List)", Subtitle = string.Format("Random data (n={0})", N) }; + var l = new Legend + { + LegendPosition = LegendPosition.LeftTop + }; + + model.Legends.Add(l); + + model.Series.Add(new ScatterErrorSeries { Title = "Measurements", ItemsSource = CreateScatterErrorPoints(N).ToList() }); + return model; + } + + [Example("Defining points by ItemsSource (IEnumerable)")] + public static PlotModel ItemsSourceEnumerable() + { + const int N = 20; + var model = new PlotModel { Title = "ScatterErrorSeries, points defined by ItemsSource (IEnumerable)", Subtitle = string.Format("Random data (n={0})", N) }; + var l = new Legend + { + LegendPosition = LegendPosition.LeftTop + }; + + model.Legends.Add(l); + model.Series.Add(new ScatterErrorSeries { Title = "Measurements", ItemsSource = CreateScatterErrorPoints(N).ToArray() }); + return model; + } + + [Example("Definining points by ItemsSource and reflection")] + public static PlotModel ItemsSourceReflection() + { + const int N = 20; + var model = new PlotModel { Title = "ScatterErrorSeries, points defined by ItemsSource (reflection)", Subtitle = string.Format("Random data (n={0})", N) }; + var l = new Legend + { + LegendPosition = LegendPosition.LeftTop + }; + + model.Legends.Add(l); + model.Series.Add(new ScatterErrorSeries + { + Title = "Measurements", + ItemsSource = CreateExamplePoints(N).ToArray(), + DataFieldX = "V1", + DataFieldY = "V2", + DataFieldErrorX = "E1", + DataFieldErrorY = "E2" + }); + return model; + } + + /// + /// Creates an example model with the specified number of points. + /// + /// The n. + /// A plot model. + private static PlotModel RandomPointsAndError(int n) + { + var model = new PlotModel { Title = "ScatterErrorSeries", Subtitle = string.Format("Random data (n={0})", n) }; + var l = new Legend + { + LegendPosition = LegendPosition.LeftTop + }; + + model.Legends.Add(l); + var s1 = new ScatterErrorSeries { Title = "Measurements" }; + s1.Points.AddRange(CreateScatterErrorPoints(n)); + model.Series.Add(s1); + return model; + } + + /// + /// Creates random example data. + /// + /// The number of points to generate. + /// A sequence of points. + private static IEnumerable CreateScatterErrorPoints(int n) + { + var random = new Random(27); + double x = 0; + double y = 0; + for (int i = 0; i < n; i++) + { + x += 2 + random.NextDouble(); + y += 1 + random.NextDouble(); + + yield return new ScatterErrorPoint(x, y, random.NextDouble(), random.NextDouble()); + } + } + + /// + /// Creates random example data. + /// + /// The number of points to generate. + /// A sequence of points. + private static IEnumerable CreateExamplePoints(int n) + { + var random = new Random(27); + double x = 0; + double y = 0; + for (int i = 0; i < n; i++) + { + x += 2 + random.NextDouble(); + y += 1 + random.NextDouble(); + + yield return new ExamplePoint { V1 = x, V2 = y, E1 = random.NextDouble(), E2 = random.NextDouble() }; + } + } + + /// + /// Represents a point with errors. + /// + public class ExamplePoint + { + /// + /// Gets or sets the first value. + /// + public double V1 { get; set; } + + /// + /// Gets or sets the second value. + /// + public double V2 { get; set; } + + /// + /// Gets or sets the first error. + /// + public double E1 { get; set; } + + /// + /// Gets or sets the second error. + /// + public double E2 { get; set; } + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/ScatterSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/ScatterSeriesExamples.cs new file mode 100644 index 0000000..f7f4fd6 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/ScatterSeriesExamples.cs @@ -0,0 +1,623 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Calculates the Least squares fit of a list of DataPoints. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using OxyPlot; + using OxyPlot.Annotations; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("ScatterSeries"), Tags("Series")] + public class ScatterSeriesExamples + { + [Example("Correlated points")] + [DocumentationExample("Series/ScatterSeries")] + public static PlotModel CorrelatedScatter() + { + return CreateCorrelatedScatter(1000); + } + + [Example("Random points")] + public static PlotModel RandomScatter() + { + return RandomScatter(32768, 0); + } + + [Example("Random points (BinSize=2)")] + public static PlotModel RandomScatter2() + { + return RandomScatter(32768, 2); + } + + [Example("Random points (BinSize=4)")] + public static PlotModel RandomScatter4() + { + return RandomScatter(32768, 4); + } + + [Example("Random points (BinSize=6)")] + public static PlotModel RandomScatter6() + { + return RandomScatter(32768, 6); + } + + [Example("Random points (BinSize=8)")] + public static PlotModel RandomScatter8() + { + return RandomScatter(32768, 8); + } + + [Example("Random points (BinSize=10)")] + public static PlotModel RandomScatter10() + { + return RandomScatter(32768, 10); + } + + [Example("Two ScatterSeries")] + public static PlotModel TwoScatterSeries() + { + var model = new PlotModel { Title = "Two ScatterSeries (with and without values)", Subtitle = "With values (squares), without values (triangles)" }; + var colorAxis = new LinearColorAxis { Position = AxisPosition.Right, Key = "ColorAxis", Palette = OxyPalettes.Jet(30), Minimum = -1, Maximum = 1 }; + model.Axes.Add(colorAxis); + model.Series.Add(CreateRandomScatterSeries(50, MarkerType.Triangle, false, false, null)); + model.Series.Add(CreateRandomScatterSeries(50, MarkerType.Square, false, true, colorAxis)); + return model; + } + + [Example("LabelFormatString")] + public static PlotModel LabelFormatString() + { + var model = new PlotModel { Title = "ScatterSeries with LabelFormatString" }; + var s = CreateRandomScatterSeries(50, MarkerType.Square, false, false, null); + s.LabelFormatString = "{1:0.###}"; + model.Series.Add(s); + return model; + } + + private static PlotModel CreateRandomScatterSeriesWithColorAxisPlotModel(int n, OxyPalette palette, MarkerType markerType, AxisPosition colorAxisPosition, OxyColor highColor, OxyColor lowColor) + { + var model = new PlotModel { Title = string.Format("ScatterSeries (n={0})", n), Background = OxyColors.LightGray }; + var colorAxis = new LinearColorAxis { Position = colorAxisPosition, Palette = palette, Minimum = -1, Maximum = 1, HighColor = highColor, LowColor = lowColor }; + model.Axes.Add(colorAxis); + model.Series.Add(CreateRandomScatterSeries(n, markerType, false, true, colorAxis)); + return model; + } + + private static ScatterSeries CreateRandomScatterSeries(int n, MarkerType markerType, bool setSize, bool setValue, LinearColorAxis colorAxis) + { + var s1 = new ScatterSeries + { + MarkerType = markerType, + MarkerSize = 6, + ColorAxisKey = colorAxis != null ? colorAxis.Key : null + }; + var random = new Random(13); + for (int i = 0; i < n; i++) + { + var p = new ScatterPoint((random.NextDouble() * 2.2) - 1.1, random.NextDouble()); + if (setSize) + { + p.Size = (random.NextDouble() * 5) + 5; + } + + if (setValue) + { + p.Value = (random.NextDouble() * 2.2) - 1.1; + } + + s1.Points.Add(p); + } + + return s1; + } + + [Example("Random points with random size")] + public static PlotModel RandomSize() + { + return RandomSize(1000, 8); + } + + public static PlotModel RandomSize(int n, int binsize) + { + var model = new PlotModel { Title = string.Format("ScatterSeries with random MarkerSize (n={0})", n), Subtitle = "BinSize = " + binsize }; + + var s1 = new ScatterSeries { Title = "Series 1", MarkerStrokeThickness = 0, BinSize = binsize }; + var random = new Random(13); + for (int i = 0; i < n; i++) + { + s1.Points.Add(new ScatterPoint(random.NextDouble(), random.NextDouble(), 4 + (10 * random.NextDouble()))); + } + + model.Series.Add(s1); + return model; + } + + [Example("Random points with least squares fit")] + public static PlotModel RandomWithFit() + { + const int n = 20; + var model = new PlotModel { Title = string.Format("Random data (n={0})", n) }; + var l = new Legend + { + LegendPosition = LegendPosition.LeftTop + }; + + model.Legends.Add(l); + + var s1 = new ScatterSeries { Title = "Measurements" }; + var random = new Random(7); + double x = 0; + double y = 0; + for (int i = 0; i < n; i++) + { + x += 2 + (random.NextDouble() * 10); + y += 1 + random.NextDouble(); + var p = new ScatterPoint(x, y); + s1.Points.Add(p); + } + + model.Series.Add(s1); + double a, b; + LeastSquaresFit(s1.Points, out a, out b); + model.Annotations.Add(new LineAnnotation { Slope = a, Intercept = b, Text = "Least squares fit" }); + return model; + } + + /// + /// Calculates the Least squares fit of a list of DataPoints. + /// + /// The points. + /// The slope. + /// The intercept. + public static void LeastSquaresFit(IEnumerable points, out double a, out double b) + { + // http://en.wikipedia.org/wiki/Least_squares + // http://mathworld.wolfram.com/LeastSquaresFitting.html + // http://web.cecs.pdx.edu/~gerry/nmm/course/slides/ch09Slides4up.pdf + + double Sx = 0; + double Sy = 0; + double Sxy = 0; + double Sxx = 0; + int m = 0; + foreach (var p in points) + { + Sx += p.X; + Sy += p.Y; + Sxy += p.X * p.Y; + Sxx += p.X * p.X; + m++; + } + + double d = Sx * Sx - m * Sxx; + a = 1 / d * (Sx * Sy - m * Sxy); + b = 1 / d * (Sx * Sxy - Sxx * Sy); + } + + [Example("Marker types")] + public static PlotModel MarkerTypes() + { + var model = new PlotModel { Title = "Marker types" }; + var r = new Random(12345); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Circle", MarkerType.Circle)); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Cross", MarkerType.Cross)); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Diamond", MarkerType.Diamond)); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Plus", MarkerType.Plus)); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Square", MarkerType.Square)); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Star", MarkerType.Star)); + model.Series.Add(CreateRandomScatterSeries(r, 10, "Triangle", MarkerType.Triangle)); + return model; + } + + [Example("ScatterSeries.Points")] + public static PlotModel DataPoints() + { + var model = new PlotModel { Title = "ScatterSeries (n=1000)", Subtitle = "The scatter points are added to the Points collection." }; + var series = new ScatterSeries(); + series.Points.AddRange(CreateRandomScatterPoints(1000)); + model.Series.Add(series); + return model; + } + + [Example("ScatterSeries.ItemsSource")] + public static PlotModel FromItemsSource() + { + var model = new PlotModel { Title = "ScatterSeries (n=1000)", Subtitle = "The scatter points are defined in the ItemsSource property." }; + model.Series.Add(new ScatterSeries + { + ItemsSource = CreateRandomScatterPoints(1000), + }); + return model; + } + + [Example("ScatterSeries.ItemsSource + Mapping")] + public static PlotModel FromMapping() + { + var model = new PlotModel { Title = "ScatterSeries (n=1000)", Subtitle = "The scatter points are defined by a mapping from the ItemsSource." }; + model.Series.Add(new ScatterSeries + { + ItemsSource = CreateRandomDataPoints(1000), + Mapping = item => new ScatterPoint(((DataPoint)item).X, ((DataPoint)item).Y) + }); + return model; + } + + [Example("ScatterSeries.ItemsSource + reflection")] + public static PlotModel FromItemsSourceReflection() + { + var model = new PlotModel { Title = "ScatterSeries (n=1000)", Subtitle = "The scatter points are defined by reflection from the ItemsSource." }; + model.Series.Add(new ScatterSeries + { + ItemsSource = CreateRandomDataPoints(1000), + DataFieldX = "X", + DataFieldY = "Y" + }); + return model; + } + + [Example("ScatterSeries with ColorAxis Rainbow(16)")] + public static PlotModel ColorMapRainbow16() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Rainbow(16), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Hue(30) Star")] + public static PlotModel ColorMapHue30() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Hue(30), MarkerType.Star, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Hot(64)")] + public static PlotModel ColorMapHot64() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Hot(64), MarkerType.Triangle, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Cool(32)")] + public static PlotModel ColorMapCool32() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Cool(32), MarkerType.Circle, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Gray(32)")] + public static PlotModel ColorMapGray32() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Gray(32), MarkerType.Diamond, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Jet(32)")] + public static PlotModel ColorMapJet32() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Jet(32), MarkerType.Plus, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Hot with extreme colors")] + public static PlotModel ColorMapHot64Extreme() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Hot(64), MarkerType.Square, AxisPosition.Right, OxyColors.Magenta, OxyColors.Green); + } + + [Example("ScatterSeries with ColorAxis Hot (top legend)")] + public static PlotModel ColorMapHot64ExtremeTopLegend() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Hot(64), MarkerType.Cross, AxisPosition.Top, OxyColors.Magenta, OxyColors.Green); + } + [Example("ScatterSeries with ColorAxis Hot(16) N=31000")] + public static PlotModel ColorMapHot16Big() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(31000, OxyPalettes.Hot(16), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis BlueWhiteRed (3)")] + public static PlotModel ColorMapBlueWhiteRed3() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.BlueWhiteRed(3), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis BlueWhiteRed (9)")] + public static PlotModel ColorMapBlueWhiteRed9() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.BlueWhiteRed(9), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis BlueWhiteRed (256)")] + public static PlotModel ColorMapBlueWhiteRed256() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.BlueWhiteRed(256), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis BlackWhiteRed (9)")] + public static PlotModel ColorMapBlackWhiteRed9() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.BlackWhiteRed(9), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis BlackWhiteRed (9) top legend")] + public static PlotModel ColorMapBlackWhiteRed9TopLegend() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.BlackWhiteRed(9), MarkerType.Square, AxisPosition.Top, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Viridis")] + public static PlotModel ColorMapViridis() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Viridis(), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Plasma")] + public static PlotModel ColorMapPlasma() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Plasma(), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Magma")] + public static PlotModel ColorMapMagma() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Magma(), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Inferno")] + public static PlotModel ColorMapInferno() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Inferno(), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with ColorAxis Cividis")] + public static PlotModel ColorMapCividis() + { + return CreateRandomScatterSeriesWithColorAxisPlotModel(2500, OxyPalettes.Cividis(), MarkerType.Square, AxisPosition.Right, OxyColors.Undefined, OxyColors.Undefined); + } + + [Example("ScatterSeries with single-selected items")] + public static PlotModel SingleSelectItems() + { + var model = RandomScatter(10, 8); + model.Subtitle = "Click to select a point"; + + model.SelectionColor = OxyColors.Red; + + var series = model.Series[0]; + + series.SelectionMode = SelectionMode.Single; + + series.SelectItem(3); + series.SelectItem(5); + + series.MouseDown += (s, e) => + { + var index = (int)e.HitTestResult.Index; + series.SelectItem(index); + model.InvalidatePlot(false); + e.Handled = true; + }; + model.MouseDown += (s, e) => + { + series.ClearSelection(); + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("ScatterSeries with multi-selected items")] + public static PlotModel MultiSelectItems() + { + var model = RandomScatter(10, 8); + model.Subtitle = "Click to toggle point selection"; + + model.SelectionColor = OxyColors.Red; + + var series = model.Series[0]; + + series.SelectionMode = SelectionMode.Multiple; + + series.SelectItem(3); + series.SelectItem(5); + + series.MouseDown += (s, e) => + { + var index = (int)e.HitTestResult.Index; + + // Toggle the selection state for this item + if (series.IsItemSelected(index)) + { + series.UnselectItem(index); + } + else + { + series.SelectItem(index); + } + + model.InvalidatePlot(false); + e.Handled = true; + }; + + model.MouseDown += (s, e) => + { + series.ClearSelection(); + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("ScatterSeries with SelectionMode.All (no tracker)")] + public static PlotModel AllSelected() + { + return AllSelected(false); + } + + [Example("ScatterSeries with SelectionMode.All (with tracker)")] + public static PlotModel AllSelectedWithTracker() + { + return AllSelected(true); + } + + private static PlotModel AllSelected(bool showTracker) + { + var model = RandomScatter(10, 8); + model.Subtitle = "Click to select all points"; + + model.SelectionColor = OxyColors.Red; + + var series = model.Series[0]; + + series.SelectionMode = SelectionMode.All; + + series.MouseDown += (s, e) => + { + series.Select(); + model.InvalidatePlot(false); + e.Handled = !showTracker; + }; + + model.MouseDown += (s, e) => + { + if (e.HitTestResult != null && showTracker) + { + return; + } + + series.ClearSelection(); + model.InvalidatePlot(false); + e.Handled = true; + }; + + return model; + } + + [Example("TrackerFormatString")] + public static PlotModel TrackerFormatString() + { + var model = new PlotModel { Title = "TrackerFormatString" }; + + var s1 = new ScatterSeries { TrackerFormatString = "{Sum:0.0}", DataFieldX = "X", DataFieldY = "Y" }; + var myPoints = new List + { + new MyPoint { X = 10, Y = 40 }, + new MyPoint { X = 40, Y = 20 }, + new MyPoint { X = 60, Y = 30 } + }; + s1.ItemsSource = myPoints; + model.Series.Add(s1); + return model; + } + + public struct MyPoint + { + public double X { get; set; } + + public double Y { get; set; } + + public double Sum + { + get + { + // calculated on request + return this.X + this.Y; + } + } + } + + private static PlotModel RandomScatter(int n, int binSize) + { + var model = new PlotModel { Title = string.Format("ScatterSeries (n={0})", n), Subtitle = binSize > 0 ? "BinSize = " + binSize : "No 'binning'" }; + + var s1 = new ScatterSeries() + { + Title = "Series 1", + MarkerType = MarkerType.Diamond, + MarkerStrokeThickness = 0, + BinSize = binSize + }; + + var random = new Random(1); + for (int i = 0; i < n; i++) + { + s1.Points.Add(new ScatterPoint(random.NextDouble(), random.NextDouble())); + } + + model.Series.Add(s1); + return model; + } + + private static PlotModel CreateCorrelatedScatter(int n) + { + var model = new PlotModel { Title = string.Format("Correlated ScatterSeries (n={0})", n) }; + + var s1 = new ScatterSeries + { + Title = "Series 1", + MarkerType = MarkerType.Diamond, + MarkerStrokeThickness = 0, + }; + + var random = new Random(1); + for (int i = 0; i < n; i++) + { + var x = GetNormalDistributedValue(random); + var y = 2 * x * x + GetNormalDistributedValue(random); + s1.Points.Add(new ScatterPoint(x, y)); + } + + model.Series.Add(s1); + return model; + } + + private static ScatterSeries CreateRandomScatterSeries(Random r, int n, string title, MarkerType markerType) + { + var s1 = new ScatterSeries { Title = title, MarkerType = markerType, MarkerStroke = OxyColors.Black, MarkerStrokeThickness = 1.0 }; + for (int i = 0; i < n; i++) + { + double x = r.NextDouble() * 10; + double y = r.NextDouble() * 10; + var p = new ScatterPoint(x, y); + s1.Points.Add(p); + } + + return s1; + } + + private static double GetNormalDistributedValue(Random rnd) + { + var d1 = rnd.NextDouble(); + var d2 = rnd.NextDouble(); + return Math.Sqrt(-2.0 * Math.Log(d1)) * Math.Sin(2.0 * Math.PI * d2); + } + + private static List CreateRandomDataPoints(int n) + { + return CreateRandomScatterPoints(n).Select(sp => new DataPoint(sp.X, sp.Y)).ToList(); + } + + private static List CreateRandomScatterPoints(int n) + { + var r = new Random(12345); + + var points = new List(); + for (int i = 0; i < n; i++) + { + double x = r.NextDouble() * 10; + double y = r.NextDouble() * 10; + var p = new ScatterPoint(x, y); + points.Add(p); + } + + return points; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/StairStepSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/StairStepSeriesExamples.cs new file mode 100644 index 0000000..0e96edf --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/StairStepSeriesExamples.cs @@ -0,0 +1,230 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for the . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Series; + using OxyPlot.Legends; + + /// + /// Provides examples for the . + /// + [Examples("StairStepSeries"), Tags("Series")] + public static class StairStepSeriesExamples + { + [Example("StairStepSeries")] + [DocumentationExample("Series/StairStepSeries")] + public static PlotModel StairStepSeries() + { + return CreateExampleModel(new StairStepSeries()); + } + + [Example("StairStepSeries with labels")] + public static PlotModel StairStepSeriesWithLabels() + { + return CreateExampleModel(new StairStepSeries { LabelFormatString = "{1:0.00}" }); + } + + [Example("StairStepSeries with markers")] + public static PlotModel StairStepSeriesWithMarkers() + { + return CreateExampleModel(new StairStepSeries + { + Color = OxyColors.SkyBlue, + MarkerType = MarkerType.Circle, + MarkerSize = 6, + MarkerStroke = OxyColors.White, + MarkerFill = OxyColors.SkyBlue, + MarkerStrokeThickness = 1.5 + }); + } + + [Example("StairStepSeries with thin vertical lines")] + public static PlotModel StairStepSeriesThinVertical() + { + return CreateExampleModel(new StairStepSeries + { + StrokeThickness = 3, + VerticalStrokeThickness = 0.4, + MarkerType = MarkerType.None + }); + } + + [Example("StairStepSeries with dashed vertical lines")] + public static PlotModel StairStepSeriesDashedVertical() + { + return CreateExampleModel(new StairStepSeries + { + VerticalLineStyle = LineStyle.Dash, + MarkerType = MarkerType.None + }); + } + + [Example("StairStepSeries with invalid points")] + public static PlotModel StairStepSeriesWithInvalidPoints() + { + var model = new PlotModel + { + Title = "StairStepSeries with invalid points", + Subtitle = "Horizontal lines do not continue", + }; + + PopulateInvalidPointExampleModel(model, x => DataPoint.Undefined); + + return model; + } + + [Example("StairStepSeries with invalid Y")] + public static PlotModel StairStepSeriesWithInvalidY() + { + var model = new PlotModel + { + Title = "StairStepSeries with invalid Y", + Subtitle = "Horizontal lines continue until X of point with invalid Y", + }; + + PopulateInvalidPointExampleModel(model, x => new DataPoint(x, double.NaN)); + + return model; + } + + [Example("StairStepSeries with non-monotonic X")] + public static PlotModel StairStepSeriesWithNonmonotonicX() + { + var model = new PlotModel + { + Title = "StairStepSeries with non-monotonic X", + Subtitle = "Lines form a boxed I-beam", + }; + + var iBeamSeries = new StairStepSeries + { + MarkerType = MarkerType.Circle, + VerticalLineStyle = LineStyle.Dash, + VerticalStrokeThickness = 4, + }; + iBeamSeries.Points.Add(new DataPoint(1, 1)); + iBeamSeries.Points.Add(new DataPoint(3, 1)); + iBeamSeries.Points.Add(new DataPoint(2, 3)); + iBeamSeries.Points.Add(new DataPoint(1, 3)); + iBeamSeries.Points.Add(new DataPoint(3, 3)); + model.Series.Add(iBeamSeries); + + var boxBRSeries = new StairStepSeries + { + MarkerType = MarkerType.Circle, + VerticalLineStyle = LineStyle.Dash, + VerticalStrokeThickness = 4, + }; + boxBRSeries.Points.Add(new DataPoint(1, 0)); + boxBRSeries.Points.Add(new DataPoint(2, 0)); + boxBRSeries.Points.Add(new DataPoint(0, 0)); + boxBRSeries.Points.Add(new DataPoint(4, 0)); + boxBRSeries.Points.Add(new DataPoint(4, 4)); + model.Series.Add(boxBRSeries); + + var boxTLSeries = new StairStepSeries + { + MarkerType = MarkerType.Circle, + VerticalLineStyle = LineStyle.Dash, + VerticalStrokeThickness = 4, + }; + boxTLSeries.Points.Add(new DataPoint(3, 4)); + boxTLSeries.Points.Add(new DataPoint(2, 4)); + boxTLSeries.Points.Add(new DataPoint(4, 4)); + boxTLSeries.Points.Add(new DataPoint(0, 4)); + boxTLSeries.Points.Add(new DataPoint(0, 0)); + model.Series.Add(boxTLSeries); + + return model; + } + + /// + /// Creates an example model and fills the specified series with points. + /// + /// The series. + /// A plot model. + private static PlotModel CreateExampleModel(DataPointSeries series) + { + var model = new PlotModel { Title = "StairStepSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + series.Title = "sin(x)"; + for (double x = 0; x < Math.PI * 2; x += 0.5) + { + series.Points.Add(new DataPoint(x, Math.Sin(x))); + } + + model.Series.Add(series); + return model; + } + + private static void PopulateInvalidPointExampleModel(PlotModel model, Func getInvalidPoint) + { + model.Legends.Add(new Legend() + { + LegendOrientation = LegendOrientation.Horizontal, + LegendPlacement = LegendPlacement.Outside, + LegendPosition = LegendPosition.BottomCenter, + }); + + var series1 = new StairStepSeries + { + Title = "Invalid First Point", + MarkerType = MarkerType.Circle, + }; + series1.Points.Add(getInvalidPoint(0)); + series1.Points.Add(new DataPoint(1, 3.5)); + series1.Points.Add(new DataPoint(2, 4.0)); + series1.Points.Add(new DataPoint(3, 4.5)); + model.Series.Add(series1); + + var series2 = new StairStepSeries + { + Title = "Invalid Second Point", + MarkerType = MarkerType.Circle, + }; + series2.Points.Add(new DataPoint(0, 2.0)); + series2.Points.Add(getInvalidPoint(1)); + series2.Points.Add(new DataPoint(2, 3.0)); + series2.Points.Add(new DataPoint(3, 3.5)); + model.Series.Add(series2); + + var series3 = new StairStepSeries + { + Title = "Invalid Penultimate Point", + MarkerType = MarkerType.Circle, + }; + series3.Points.Add(new DataPoint(0, 1.0)); + series3.Points.Add(new DataPoint(1, 1.5)); + series3.Points.Add(getInvalidPoint(2)); + series3.Points.Add(new DataPoint(3, 2.5)); + model.Series.Add(series3); + + var series4 = new StairStepSeries + { + Title = "Invalid Last Point", + MarkerType = MarkerType.Circle, + }; + series4.Points.Add(new DataPoint(0, 0.0)); + series4.Points.Add(new DataPoint(1, 0.5)); + series4.Points.Add(new DataPoint(2, 1.0)); + series4.Points.Add(getInvalidPoint(3)); + model.Series.Add(series4); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/StemSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/StemSeriesExamples.cs new file mode 100644 index 0000000..ee51e45 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/StemSeriesExamples.cs @@ -0,0 +1,62 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for the . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Series; + using OxyPlot.Legends; + + /// + /// Provides examples for the . + /// + [Examples("StemSeries"), Tags("Series")] + public static class StemSeriesExamples + { + [Example("StemSeries")] + [DocumentationExample("Series/StemSeries")] + public static PlotModel StemSeries() + { + return CreateExampleModel(new StemSeries + { + Color = OxyColors.SkyBlue, + MarkerType = MarkerType.Circle, + MarkerSize = 6, + MarkerStroke = OxyColors.White, + MarkerStrokeThickness = 1.5 + }); + } + + /// + /// Creates an example model and fills the specified series with points. + /// + /// The series. + /// A plot model. + private static PlotModel CreateExampleModel(DataPointSeries series) + { + var model = new PlotModel { Title = "StemSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + series.Title = "sin(x)"; + for (double x = 0; x < Math.PI * 2; x += 0.1) + { + series.Points.Add(new DataPoint(x, Math.Sin(x))); + } + + model.Series.Add(series); + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/ThreeColorLineSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/ThreeColorLineSeriesExamples.cs new file mode 100644 index 0000000..c361e00 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/ThreeColorLineSeriesExamples.cs @@ -0,0 +1,73 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for the ThreeColorLineSeries. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary.Series +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + using ExampleLibrary.Utilities; + + /// + /// Provides examples for the . + /// + [Examples("ThreeColorLineSeries"), Tags("Series")] + public class ThreeColorLineSeriesExamples + { + /// + /// Creates an example showing temperatures. + /// + /// A . + [Example("Temperatures")] + [DocumentationExample("Series/ThreeColorLineSeries")] + public static PlotModel ThreeColorLineSeries() + { + var model = new PlotModel { Title = "ThreeColorLineSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new ThreeColorLineSeries + { + Title = "Temperature at Eidesmoen, December 1986.", + TrackerFormatString = "December {2:0}: {4:0.0} °C", + MarkerSize = 4, + MarkerStroke = OxyColors.Black, + MarkerStrokeThickness = 1.5, + MarkerType = MarkerType.Circle, + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + StrokeThickness = 3, + }; + + var temperatures = new[] { 5, 0, 7, 7, 4, 3, 5, 5, 11, 4, 2, 3, 2, 1, 0, 2, -1, 0, 0, -3, -6, -13, -10, -10, 0, -4, -5, -4, 3, 0, -5 }; + + for (int i = 0; i < temperatures.Length; i++) + { + s1.Points.Add(new DataPoint(i + 1, temperatures[i])); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature", Unit = "°C", ExtraGridlines = new[] { 0.0 } }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Date" }); + + return model; + } + + [Example("Temperatures (Y Axis reversed)")] + public static PlotModel TwoColorLineSeriesReversed() + { + return ThreeColorLineSeries().ReverseYAxis(); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/TornadoBarSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/TornadoBarSeriesExamples.cs new file mode 100644 index 0000000..e2b34ec --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/TornadoBarSeriesExamples.cs @@ -0,0 +1,164 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + [Examples("TornadoBarSeries"), Tags("Series")] + public static class TornadoBarSeriesExamples + { + [Example("Tornado diagram 1")] + [DocumentationExample("Series/TornadoBarSeries")] + public static PlotModel TornadoDiagram1() + { + // http://en.wikipedia.org/wiki/Tornado_diagram + var model = new PlotModel { Title = "Tornado diagram 1" }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + + var s1 = new BarSeries + { + Title = "High", + IsStacked = true, + FillColor = OxyColor.FromRgb(216, 82, 85), + BaseValue = 7, + StrokeColor = OxyColors.Black, + StrokeThickness = 1 + }; + s1.Items.Add(new BarItem(1)); + s1.Items.Add(new BarItem(1)); + s1.Items.Add(new BarItem(4)); + s1.Items.Add(new BarItem(5)); + + var s2 = new BarSeries + { + Title = "Low", + IsStacked = true, + FillColor = OxyColor.FromRgb(84, 138, 209), + BaseValue = 7, + StrokeColor = OxyColors.Black, + StrokeThickness = 1 + }; + s2.Items.Add(new BarItem(-1)); + s2.Items.Add(new BarItem(-3)); + s2.Items.Add(new BarItem(-2)); + s2.Items.Add(new BarItem(-3)); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("F/X rate"); + categoryAxis.Labels.Add("Inflation"); + categoryAxis.Labels.Add("Price"); + categoryAxis.Labels.Add("Conversion"); + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, ExtraGridlines = new[] { 7.0 } }; + model.Series.Add(s1); + model.Series.Add(s2); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + [Example("Tornado diagram 2")] + public static PlotModel TornadoDiagram2() + { + var model = new PlotModel { Title = "Tornado diagram 2" }; + var l = new Legend + { + LegendPlacement = LegendPlacement.Outside + }; + + model.Legends.Add(l); + var s1 = new TornadoBarSeries { Title = "TornadoBarSeries", BaseValue = 7 }; + s1.Items.Add(new TornadoBarItem { Minimum = 6, Maximum = 8 }); + s1.Items.Add(new TornadoBarItem { Minimum = 4, Maximum = 8 }); + s1.Items.Add(new TornadoBarItem { Minimum = 5, Maximum = 11 }); + s1.Items.Add(new TornadoBarItem { Minimum = 4, Maximum = 12 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left }; + categoryAxis.Labels.Add("F/X rate"); + categoryAxis.Labels.Add("Inflation"); + categoryAxis.Labels.Add("Price"); + categoryAxis.Labels.Add("Conversion"); + var valueAxis = new LinearAxis { Position = AxisPosition.Bottom, ExtraGridlines = new[] { 7.0 }, MinimumPadding = 0.1, MaximumPadding = 0.1 }; + model.Series.Add(s1); + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + return model; + } + + [Example("Tornado diagram with various label types")] + public static PlotModel TornadoDiagramWithLabels() + { + var model = new PlotModel { Title = "Tornado Diagram" }; + var l = new Legend { LegendPlacement = LegendPlacement.Outside }; + + model.Legends.Add(l); + + var s1 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Outside}; + s1.Items.Add(new TornadoBarItem { Minimum = 6, Maximum = 8, CategoryIndex = 0}); + + var s2 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Inside }; + s2.Items.Add(new TornadoBarItem { Minimum = 4, Maximum = 8, CategoryIndex = 1 }); + + var s3 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Middle }; + s3.Items.Add(new TornadoBarItem { Minimum = 5, Maximum = 11, CategoryIndex = 2 }); + + var s4 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Base }; + s4.Items.Add(new TornadoBarItem { Minimum = 4, Maximum = 12, CategoryIndex = 3 }); + + var s5 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Outside, LabelAngle = -45 }; + s5.Items.Add(new TornadoBarItem { Minimum = 6, Maximum = 8, CategoryIndex = 4 }); + + var s6 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Inside, LabelAngle = -45 }; + s6.Items.Add(new TornadoBarItem { Minimum = 4, Maximum = 8, CategoryIndex = 5 }); + + var s7 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Middle, LabelAngle = -45 }; + s7.Items.Add(new TornadoBarItem { Minimum = 5, Maximum = 11, CategoryIndex = 6 }); + + var s8 = new TornadoBarSeries { BaseValue = 7, LabelPlacement = LabelPlacement.Base, LabelAngle = -45 }; + s8.Items.Add(new TornadoBarItem { Minimum = 4, Maximum = 12, CategoryIndex = 7 }); + + var categoryAxis = new CategoryAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0 }; + categoryAxis.Labels.Add("Labels Outside"); + categoryAxis.Labels.Add("Labels Inside"); + categoryAxis.Labels.Add("Labels Middle"); + categoryAxis.Labels.Add("Labels Base"); + categoryAxis.Labels.Add("Labels Outside (angled)"); + categoryAxis.Labels.Add("Labels Inside (angled)"); + categoryAxis.Labels.Add("Labels Middle (angled)"); + categoryAxis.Labels.Add("Labels Base (angled)"); + + var valueAxis = new LinearAxis + { + Position = AxisPosition.Bottom, + ExtraGridlines = new[] { 7.0 }, + MinimumPadding = 0.1, + MaximumPadding = 0.1 + }; + + model.Series.Add(s1); + model.Series.Add(s2); + model.Series.Add(s3); + model.Series.Add(s4); + model.Series.Add(s5); + model.Series.Add(s6); + model.Series.Add(s7); + model.Series.Add(s8); + + model.Axes.Add(categoryAxis); + model.Axes.Add(valueAxis); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/TwoColorAreaSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/TwoColorAreaSeriesExamples.cs new file mode 100644 index 0000000..971b118 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/TwoColorAreaSeriesExamples.cs @@ -0,0 +1,198 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for the . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + /// + /// Provides examples for the . + /// + [Examples("TwoColorAreaSeries"), Tags("Series")] + public class TwoColorAreaSeriesExamples + { + /// + /// Creates an example showing temperatures by a red/blue area chart. + /// + /// A . + [Example("Temperatures")] + public static PlotModel TwoColorAreaSeries() + { + var model = new PlotModel { Title = "TwoColorAreaSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new TwoColorAreaSeries + { + Title = "Temperature at Eidesmoen, December 1986.", + TrackerFormatString = "December {2:0}: {4:0.0} °C", + Color = OxyColors.Tomato, + Color2 = OxyColors.LightBlue, + MarkerFill = OxyColors.Tomato, + MarkerFill2 = OxyColors.LightBlue, + StrokeThickness = 2, + Limit = -1, + MarkerType = MarkerType.Circle, + MarkerSize = 3, + }; + + var temperatures = new[] { 5, 0, 7, 7, 4, 3, 5, 5, 11, 4, 2, 3, 2, 1, 0, 2, -1, 0, 0, -3, -6, -13, -10, -10, 0, -4, -5, -4, 3, 0, -5 }; + + for (int i = 0; i < temperatures.Length; i++) + { + s1.Points.Add(new DataPoint(i + 1, temperatures[i])); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature", Unit = "°C", ExtraGridlines = new[] { 0.0 } }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Date" }); + + return model; + } + + /// + /// Creates an example showing temperatures by a red/blue area chart. + /// + /// A . + [Example("Temperatures ver2")] + [DocumentationExample("Series/TwoColorAreaSeries")] + public static PlotModel TwoColorAreaSeries2() + { + var model = new PlotModel { Title = "TwoColorAreaSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new TwoColorAreaSeries + { + Title = "Temperature at Eidesmoen, December 1986.", + TrackerFormatString = "December {2:0}: {4:0.0} °C", + Color = OxyColors.Black, + Color2 = OxyColors.Brown, + MarkerFill = OxyColors.Red, + Fill = OxyColors.Tomato, + Fill2 = OxyColors.LightBlue, + MarkerFill2 = OxyColors.Blue, + MarkerStroke = OxyColors.Brown, + MarkerStroke2 = OxyColors.Black, + StrokeThickness = 2, + Limit = 0, + MarkerType = MarkerType.Circle, + MarkerSize = 3, + }; + + var temperatures = new[] { 5, 0, 7, 7, 4, 3, 5, 5, 11, 4, 2, 3, 2, 1, 0, 2, -1, 0, 0, -3, -6, -13, -10, -10, 0, -4, -5, -4, 3, 0, -5 }; + + for (int i = 0; i < temperatures.Length; i++) + { + s1.Points.Add(new DataPoint(i + 1, temperatures[i])); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature", Unit = "°C", ExtraGridlines = new[] { 0.0 } }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Date" }); + + return model; + } + + /// + /// Creates an example showing temperatures by a red/blue area chart. + /// + /// A . + [Example("Temperatures ver3")] + public static PlotModel TwoColorAreaSeries3() + { + var model = new PlotModel { Title = "TwoColorAreaSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new TwoColorAreaSeries + { + Title = "Temperature at Eidesmoen, December 1986.", + TrackerFormatString = "December {2:0}: {4:0.0} °C", + Color = OxyColors.Black, + Color2 = OxyColors.Brown, + MarkerFill = OxyColors.Red, + Fill = OxyColors.Tomato, + Fill2 = OxyColors.LightBlue, + MarkerFill2 = OxyColors.Blue, + MarkerStroke = OxyColors.Brown, + MarkerStroke2 = OxyColors.Black, + StrokeThickness = 1, + Limit = 0, + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + MarkerType = MarkerType.Circle, + MarkerSize = 1, + }; + + var temperatures = new[] { 5, 0, 7, 7, 4, 3, 5, 5, 11, 4, 2, 3, 2, 1, 0, 2, -1, 0, 0, -3, -6, -13, -10, -10, 0, -4, -5, -4, 3, 0, -5 }; + + for (int i = 0; i < temperatures.Length; i++) + { + s1.Points.Add(new DataPoint(i + 1, temperatures[i])); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature", Unit = "°C", ExtraGridlines = new[] { 0.0 } }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Date" }); + + return model; + } + + /// + /// Creates an example showing temperatures by a red/blue area chart. + /// + /// A . + [Example("Two polygons")] + public static PlotModel TwoColorAreaSeriesTwoPolygons() + { + var model = new PlotModel { Title = "Two polygons" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new TwoColorAreaSeries + { + Color = OxyColors.Tomato, + Color2 = OxyColors.LightBlue, + MarkerFill = OxyColors.Tomato, + MarkerFill2 = OxyColors.LightBlue, + StrokeThickness = 2, + MarkerType = MarkerType.Circle, + MarkerSize = 3, + }; + + s1.Points.AddRange(new []{new DataPoint(0, 3), new DataPoint(1, 5), new DataPoint(2, 1), new DataPoint(3, 0), new DataPoint(4, 3) }); + s1.Points2.AddRange(new[] { new DataPoint(0, -3), new DataPoint(1, -1), new DataPoint(2, 0), new DataPoint(3, -6), new DataPoint(4, -4) }); + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom}); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/TwoColorLineSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/TwoColorLineSeriesExamples.cs new file mode 100644 index 0000000..15e323f --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/TwoColorLineSeriesExamples.cs @@ -0,0 +1,76 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides examples for the . +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using ExampleLibrary.Utilities; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + using OxyPlot.Legends; + + /// + /// Provides examples for the . + /// + [Examples("TwoColorLineSeries"), Tags("Series")] + public class TwoColorLineSeriesExamples + { + /// + /// Creates an example showing temperatures by a red/blue line. + /// + /// A . + [Example("Temperatures")] + [DocumentationExample("Series/TwoColorLineSeries")] + public static PlotModel TwoColorLineSeries() + { + var model = new PlotModel { Title = "TwoColorLineSeries" }; + var l = new Legend + { + LegendSymbolLength = 24 + }; + + model.Legends.Add(l); + + var s1 = new TwoColorLineSeries + { + Title = "Temperature at Eidesmoen, December 1986.", + TrackerFormatString = "December {2:0}: {4:0.0} °C", + Color = OxyColors.Red, + Color2 = OxyColors.LightBlue, + StrokeThickness = 3, + Limit = 0, + InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline, + MarkerType = MarkerType.Circle, + MarkerSize = 4, + MarkerStroke = OxyColors.Black, + MarkerStrokeThickness = 1.5, + }; + + var temperatures = new[] { 5, 0, 7, 7, 4, 3, 5, 5, 11, 4, 2, 3, 2, 1, 0, 2, -1, 0, 0, -3, -6, -13, -10, -10, 0, -4, -5, -4, 3, 0, -5 }; + + for (int i = 0; i < temperatures.Length; i++) + { + s1.Points.Add(new DataPoint(i + 1, temperatures[i])); + } + + model.Series.Add(s1); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature", Unit = "°C", ExtraGridlines = new[] { 0.0 } }); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "Date" }); + + return model; + } + + [Example("Temperatures (Y Axis reversed)")] + public static PlotModel TwoColorLineSeriesReversed() + { + return TwoColorLineSeries().ReverseYAxis(); + } + } +} diff --git a/Source/Examples/ExampleLibrary/Series/VectorSeriesExamples.cs b/Source/Examples/ExampleLibrary/Series/VectorSeriesExamples.cs new file mode 100644 index 0000000..330e549 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Series/VectorSeriesExamples.cs @@ -0,0 +1,165 @@ +namespace ExampleLibrary +{ + using System; + using System.Collections.Generic; + using System.Linq; + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + [Examples("VectorSeries"), Tags("Series")] + public static class VectorSeriesExamples + { + private static readonly Func dpeaksdx = (x, y) => + -10 * ((1 / 5 - 3 * Math.Pow(x, 2)) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(y, 2)) - 2 * x * (x / 5 - Math.Pow(x, 3) - Math.Pow(y, 5)) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(y, 2))) + 0.6666666666666666 * (1 + x) * Math.Exp(-Math.Pow(1 + x, 2) - Math.Pow(y, 2)) + 3 * (-2 * (1 - x) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(1 + y, 2)) - 2 * x * Math.Pow(1 - x, 2) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(1 + y, 2))); + + private static readonly Func dpeaksdy = (x, y) => + -10 * (-5 * Math.Pow(y, 4) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(y, 2)) - 2 * y * (x / 5 - Math.Pow(x, 3) - Math.Pow(y, 5)) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(y, 2))) + 0.6666666666666666 * y * Math.Exp(-Math.Pow(1 + x, 2) - Math.Pow(y, 2)) - 6 * Math.Pow(1 - x, 2) * (1 + y) * Math.Exp(-Math.Pow(x, 2) - Math.Pow(1 + y, 2)); + + [Example("VectorSeries")] + public static PlotModel FromItems() + { + var model = GetModel(true, out _); + return model; + } + + [Example("VectorSeries (Veeness = 2)")] + public static PlotModel FromItemsVeeness() + { + var model = GetModel(true, out var series); + series.ArrowVeeness = 2; + return model; + } + + [Example("VectorSeries (Vector Origin and Label position)")] + public static PlotModel FromItemsVectorOriginAndLabelPosition() + { + var model = GetModel(true, out var series); + series.ArrowLabelPosition = 0.25; + series.ArrowStartPosition = 0.5; + return model; + } + + [Example("VectorSeries (without ColorAxis)")] + public static PlotModel FromItemsWithoutColorAxis() + { + var model = GetModel(false, out _); + return model; + } + + [Example("Vector Field")] + [DocumentationExample("Series/VectorSeries")] + public static PlotModel VectorField() + { + var model = new PlotModel { Title = "Peaks (Gradient)" }; + var vs = new VectorSeries(); + var columnCoordinates = ArrayBuilder.CreateVector(-3, 3, 0.25); + var rowCoordinates = ArrayBuilder.CreateVector(-3.1, 3.1, 0.25); + vs.ArrowVeeness = 1; + vs.ArrowStartPosition = 0.5; + vs.ItemsSource = columnCoordinates.SelectMany(x => rowCoordinates.Select(y => new VectorItem(new DataPoint(x, y), new DataVector(dpeaksdx(x, y) / 40, dpeaksdy(x, y) / 40), double.NaN))).ToList(); + model.Series.Add(vs); + return model; + } + + private static PlotModel GetModel(bool includeColorAxis, out VectorSeries series) + { + const int NumberOfItems = 100; + var model = new PlotModel { Title = "VectorSeries (Veeness = 2)" }; + + var rand = new Random(1); + var w = 100.0; + var h = 100.0; + var max = 10.0; + + if (includeColorAxis) + { + model.Axes.Add(new LinearColorAxis + { + Position = AxisPosition.Right, + Palette = new OxyPalette(OxyPalettes.Cool(10).Colors.Select(c => OxyColor.FromAColor(100, c))), + Minimum = 0.0, + Maximum = max, + }); + } + + model.Axes.Add(new LinearAxis() + { + Position = AxisPosition.Bottom, + Minimum = -max, + Maximum = w + max, + }); + + model.Axes.Add(new LinearAxis() + { + Position = AxisPosition.Left, + Minimum = -max, + Maximum = h + max, + }); + + series = new VectorSeries() { LabelFontSize = 12 }; + for (int i = NumberOfItems - 1; i >= 0; i--) + { + var ang = rand.NextDouble() * Math.PI * 2.0; + var mag = rand.NextDouble() * max; + + var origin = new DataPoint(rand.NextDouble() * w, rand.NextDouble() * h); + var direction = new DataVector(Math.Cos(ang) * mag, Math.Sin(ang) * mag); + series.Items.Add(new VectorItem(origin, direction, mag)); + } + + model.Series.Add(series); + + return model; + } + + [Example("VectorSeries on Log Axis")] + [DocumentationExample("Series/VectorSeries")] + public static PlotModel LogarithmicYAxis() + { + const int NumberOfItems = 100; + var model = new PlotModel { Title = "VectorSeries" }; + + var rand = new Random(1); + var w = 100.0; + var h = 100.0; + var max = 50.0; + + model.Axes.Add(new LinearColorAxis + { + Position = AxisPosition.Right, + Palette = OxyPalettes.Cool(10), + Minimum = 0.0, + Maximum = max, + }); + + model.Axes.Add(new LinearAxis() + { + Position = AxisPosition.Bottom, + Minimum = -max, + Maximum = w + max, + }); + model.Axes.Add(new LogarithmicAxis() + { + Position = AxisPosition.Left, + Minimum = 1, + Maximum = h + max, + }); + + var s = new VectorSeries() { LabelFontSize = 12 }; + for (int i = NumberOfItems - 1; i >= 0; i--) + { + var ang = rand.NextDouble() * Math.PI * 2.0; + var mag = rand.NextDouble() * max; + + var origin = new DataPoint(rand.NextDouble() * w, rand.NextDouble() * h + 1); + var direction = new DataVector(Math.Cos(ang) * mag, Math.Sin(ang) * mag); + s.Items.Add(new VectorItem(origin, direction, mag)); + } + + model.Series.Add(s); + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Showcases/ShowCases.cs b/Source/Examples/ExampleLibrary/Showcases/ShowCases.cs new file mode 100644 index 0000000..bd167eb --- /dev/null +++ b/Source/Examples/ExampleLibrary/Showcases/ShowCases.cs @@ -0,0 +1,115 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Showcase models +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Showcase models + /// + [Examples("1 ShowCases")] + [Tags("Showcase")] + public class ShowCases + { + [Example("Normal distribution")] + public static PlotModel CreateNormalDistributionModel() + { + // http://en.wikipedia.org/wiki/Normal_distribution + + var plot = new PlotModel + { + Title = "Normal distribution", + Subtitle = "Probability density function" + }; + + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Left, + Minimum = -0.05, + Maximum = 1.05, + MajorStep = 0.2, + MinorStep = 0.05, + TickStyle = TickStyle.Inside + }); + plot.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + Minimum = -5.25, + Maximum = 5.25, + MajorStep = 1, + MinorStep = 0.25, + TickStyle = TickStyle.Inside + }); + plot.Series.Add(CreateNormalDistributionSeries(-5, 5, 0, 0.2)); + plot.Series.Add(CreateNormalDistributionSeries(-5, 5, 0, 1)); + plot.Series.Add(CreateNormalDistributionSeries(-5, 5, 0, 5)); + plot.Series.Add(CreateNormalDistributionSeries(-5, 5, -2, 0.5)); + return plot; + } + + [Example("Average (Mean) monthly temperatures in 2003")] + public static PlotModel LineLegendPositionAtEnd() + { + // http://www.perceptualedge.com/example2.php + var model = new PlotModel { Title = "Average (Mean) monthly temperatures in 2003", PlotMargins = new OxyThickness(60, 4, 60, 40), PlotAreaBorderThickness = new OxyThickness(0), IsLegendVisible = false }; + + const string TrackerFormatString = "{0}: {4:0.0}ºF"; + var phoenix = new LineSeries { Title = "Phoenix", LineLegendPosition = LineLegendPosition.End, TrackerFormatString = TrackerFormatString }; + var raleigh = new LineSeries { Title = "Raleigh", LineLegendPosition = LineLegendPosition.End, TrackerFormatString = TrackerFormatString }; + var minneapolis = new LineSeries { Title = "Minneapolis", LineLegendPosition = LineLegendPosition.End, TrackerFormatString = TrackerFormatString }; + + var phoenixTemps = new[] { 52.1, 55.1, 59.7, 67.7, 76.3, 84.6, 91.2, 89.1, 83.8, 72.2, 59.8, 52.5 }; + var raleighTemps = new[] { 40.5, 42.2, 49.2, 59.5, 67.4, 74.4, 77.5, 76.5, 70.6, 60.2, 50.0, 41.2 }; + var minneapolisTemps = new[] { 12.2, 16.5, 28.3, 45.1, 57.1, 66.9, 71.9, 70.2, 60.0, 50.0, 32.4, 18.6 }; + + for (int i = 0; i < 12; i++) + { + phoenix.Points.Add(new DataPoint(i, phoenixTemps[i])); + raleigh.Points.Add(new DataPoint(i, raleighTemps[i])); + minneapolis.Points.Add(new DataPoint(i, minneapolisTemps[i])); + } + + model.Series.Add(phoenix); + model.Series.Add(raleigh); + model.Series.Add(minneapolis); + + var categoryAxis = new CategoryAxis + { + AxislineStyle = LineStyle.Solid + }; + categoryAxis.Labels.AddRange(new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }); + model.Axes.Add(categoryAxis); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Fahrenheit", AxislineStyle = LineStyle.Solid }); + + return model; + } + + public static DataPointSeries CreateNormalDistributionSeries(double x0, double x1, double mean, double variance, int n = 1001) + { + var ls = new LineSeries + { + Title = string.Format("μ={0}, σ²={1}", mean, variance) + }; + + for (int i = 0; i < n; i++) + { + double x = x0 + ((x1 - x0) * i / (n - 1)); + double f = 1.0 / Math.Sqrt(2 * Math.PI * variance) * Math.Exp(-(x - mean) * (x - mean) / 2 / variance); + ls.Points.Add(new DataPoint(x, f)); + } + + return ls; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Showcases/ShowMeTheNumbersExamples.cs b/Source/Examples/ExampleLibrary/Showcases/ShowMeTheNumbersExamples.cs new file mode 100644 index 0000000..db0762d --- /dev/null +++ b/Source/Examples/ExampleLibrary/Showcases/ShowMeTheNumbersExamples.cs @@ -0,0 +1,361 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Examples from the book "Show Me the Numbers" by Stephen Few +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System.Collections.Generic; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Examples from the book "Show Me the Numbers" by Stephen Few + /// + [Examples("Examples from the book 'Show Me the Numbers'"), Tags("Showcase")] + public class ShowMeTheNumbersExamples + { + /// + /// The graph 1. + /// + /// + [Example("Q1 2003 Calls by Region")] + public static PlotModel Graph1() + { + var pm = new PlotModel { Title = "Q1 2003 Calls by Region", PlotAreaBorderThickness = new OxyThickness(0) }; + var categoryAxis = new CategoryAxis + { + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.None, + Key = "y" + }; + categoryAxis.Labels.AddRange(new[] { "North", "East", "South", "West" }); + pm.Axes.Add(categoryAxis); + pm.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + Maximum = 6000, + MajorStep = 1000, + MinorStep = 1000, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Outside, + StringFormat = "#,0", + Key = "x" + }); + var series = new BarSeries { FillColor = OxyColors.Black, XAxisKey = "x", YAxisKey = "y" }; + series.Items.Add(new BarItem { Value = 3000 }); + series.Items.Add(new BarItem { Value = 4500 }); + series.Items.Add(new BarItem { Value = 2100 }); + series.Items.Add(new BarItem { Value = 4800 }); + pm.Series.Add(series); + return pm; + } + + /// + /// The graph 2. + /// + /// + [Example("2003 Sales")] + public static PlotModel Graph2() + { + var pm = new PlotModel + { + Title = "2003 Sales", + PlotAreaBorderThickness = new OxyThickness(0), + IsLegendVisible = false + }; + var sales1 = new[] { 1000, 1010, 1020, 1010, 1020, 1030, 1000, 500, 1000, 900, 900, 1000 }; + var sales2 = new[] { 2250, 2500, 2750, 2500, 2750, 3000, 2500, 2750, 3100, 2800, 3100, 3500 }; + var categoryAxis = new CategoryAxis + { + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.None + }; + categoryAxis.Labels.AddRange(new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }); + pm.Axes.Add(categoryAxis); + pm.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + Maximum = 4000, + MajorStep = 500, + MinorStep = 500, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Outside, + StringFormat = "#,0" + }); + var s1 = new LineSeries { Color = OxyColors.Orange }; + for (int i = 0; i < 12; i++) + { + s1.Points.Add(new DataPoint(i, sales1[i])); + } + + var s2 = new LineSeries { Color = OxyColors.Gray }; + for (int i = 0; i < 12; i++) + { + s2.Points.Add(new DataPoint(i, sales2[i])); + } + + pm.Series.Add(s1); + pm.Series.Add(s2); + return pm; + } + + /// + /// The graph 3. + /// + /// + [Example("Headcount")] + public static PlotModel Graph3() + { + var pm = new PlotModel + { + Title = "Headcount", + PlotAreaBorderThickness = new OxyThickness(0), + PlotMargins = new OxyThickness(100, 40, 20, 40) + }; + var values = new Dictionary { + { "Manufacturing", 240 }, + { "Sales", 160 }, + { "Engineering", 50 }, + { "Operations", 45 }, + { "Finance", 40 }, + { "Info Systems", 39 }, + { "Legal", 25 }, + { "Marketing", 10 } + }; + pm.Axes.Add( + new CategoryAxis + { + Position = AxisPosition.Left, + ItemsSource = values, + LabelField = "Key", + TickStyle = TickStyle.None, + AxisTickToLabelDistance = 10, + StartPosition = 1, + EndPosition = 0 + }); + pm.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Minimum = 0, Maximum = 250, MajorStep = 50, MinorStep = 50, AxislineStyle = LineStyle.Solid, TickStyle = TickStyle.Outside, MinimumPadding = 0, MaximumPadding = 0 }); + pm.Series.Add(new BarSeries { FillColor = OxyColors.Black, ItemsSource = values, ValueField = "Value" }); + return pm; + } + + /// + /// The graph 4. + /// + /// + [Example("Regional % of Total Expenses")] + public static PlotModel Graph4() + { + var pm = new PlotModel { Title = "Regional % of Total Expenses", PlotAreaBorderThickness = new OxyThickness(0) }; + var categoryAxis = new CategoryAxis + { + TickStyle = TickStyle.None, + GapWidth = 0, + Key = "y" + }; + categoryAxis.Labels.AddRange(new[] { "West\n34%", "East\n30%", "North\n20%", "South\n16%" }); + pm.Axes.Add(categoryAxis); + + pm.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + Maximum = 0.35 + double.Epsilon, + MajorStep = 0.05, + MinorStep = 0.05, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Outside, + StringFormat = "P0", + Key = "x" + }); + + var series = new BarSeries + { + BarWidth = 1.0, + StrokeColor = OxyColors.DarkGray, + StrokeThickness = 1.0, + FillColor = OxyColors.Black, + XAxisKey = "x", + YAxisKey = "y" + }; + series.Items.Add(new BarItem { Value = 0.34 }); + series.Items.Add(new BarItem { Value = 0.3 }); + series.Items.Add(new BarItem { Value = 0.2 }); + series.Items.Add(new BarItem { Value = 0.16 }); + pm.Series.Add(series); + return pm; + } + + /// + /// The graph 5. + /// + /// + [Example("Actual to Plan Variance")] + public static PlotModel Graph5() + { + var pm = new PlotModel { Title = "Actual to Plan Variance", PlotAreaBorderThickness = new OxyThickness(0) }; + var values = new Dictionary(); + values.Add("Sales", 7); + values.Add("Marketing", -7); + values.Add("Systems", -2); + values.Add("HR", -17); + values.Add("Finance", 5); + pm.Axes.Add(new CategoryAxis { ItemsSource = values, LabelField = "Key", TickStyle = TickStyle.None, Key = "y" }); + pm.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = -20, + Maximum = 10, + MinorStep = 5, + MajorStep = 5, + Layer = AxisLayer.AboveSeries, + AxislineStyle = LineStyle.Solid, + ExtraGridlines = new double[] { 0 }, + ExtraGridlineColor = OxyColors.Black, + ExtraGridlineThickness = 3, + TickStyle = TickStyle.Outside, + StringFormat = "+0;-0;0", + Key = "x" + }); + pm.Series.Add( + new BarSeries + { + FillColor = OxyColors.Orange, + NegativeFillColor = OxyColors.Gray, + ItemsSource = values, + ValueField = "Value", + XAxisKey = "x", + YAxisKey = "y" + }); + return pm; + } + + /// + /// The graph 6. + /// + /// + [Example("Order Count by Order Size")] + public static PlotModel Graph6() + { + var pm = new PlotModel + { + Title = "Order Count by Order Size", + PlotAreaBorderThickness = new OxyThickness(0), + PlotMargins = new OxyThickness(60, 4, 4, 60) + }; + var values = new Dictionary + { + { " <$10", 5000 }, + { ">=$10\n &\n <$20", 1500 }, + { ">=$20\n &\n <$30", 1000 }, + { ">=$40\n &\n <$40", 500 }, + { ">=$40", 200 } + }; + pm.Axes.Add(new CategoryAxis + { + AxislineStyle = LineStyle.Solid, + ItemsSource = values, + LabelField = "Key", + TickStyle = TickStyle.None, + Key = "y" + }); + pm.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 0, + Maximum = 6000, + MajorStep = 1000, + MinorStep = 1000, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Outside, + StringFormat = "+0;-0;0", + Key = "x" + }); + pm.Series.Add(new BarSeries { FillColor = OxyColors.Orange, ItemsSource = values, ValueField = "Value", XAxisKey = "x", YAxisKey = "y" }); + return pm; + } + + /// + /// The graph 7. + /// + /// + [Example("Correlation of Employee Heights and Salaries")] + public static PlotModel Graph7() + { + var pm = new PlotModel + { + Title = "Correlation of Employee Heights and Salaries", + PlotAreaBorderThickness = new OxyThickness(0) + }; + var values = new[] + { + new DataPoint(62, 39000), + new DataPoint(66, 44000), + new DataPoint(64, 50000), + new DataPoint(66, 49500), + new DataPoint(67, 52000), + new DataPoint(68, 50000), + new DataPoint(66, 56000), + new DataPoint(67, 56000), + new DataPoint(72, 56000), + new DataPoint(68, 58000), + new DataPoint(69, 62000), + new DataPoint(71, 63000), + new DataPoint(65, 64000), + new DataPoint(68, 71000), + new DataPoint(72, 72000), + new DataPoint(74, 69000), + new DataPoint(74, 79000), + new DataPoint(77, 81000) + }; + pm.Axes.Add( + new LinearAxis + { + Position = AxisPosition.Left, + Minimum = 30000, + Maximum = 90000, + MajorStep = 10000, + MinorStep = 10000, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Outside, + StringFormat = "0,0" + }); + pm.Axes.Add(new LinearAxis + { + Position = AxisPosition.Bottom, + Minimum = 60, + Maximum = 80, + MajorStep = 5, + MinorStep = 5, + AxislineStyle = LineStyle.Solid, + TickStyle = TickStyle.Outside + }); + pm.Series.Add( + new ScatterSeries + { + ItemsSource = values, + MarkerType = MarkerType.Circle, + MarkerSize = 3.0, + MarkerFill = OxyColors.White, + MarkerStroke = OxyColors.Black, + DataFieldX = "X", + DataFieldY = "Y" + }); + return pm; + } + + } +} diff --git a/Source/Examples/ExampleLibrary/Utilities/PlotModelUtilities.cs b/Source/Examples/ExampleLibrary/Utilities/PlotModelUtilities.cs new file mode 100644 index 0000000..d04c2a7 --- /dev/null +++ b/Source/Examples/ExampleLibrary/Utilities/PlotModelUtilities.cs @@ -0,0 +1,331 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides utility functions for PlotModel used in examples. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary.Utilities +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + /// + /// Provides utility functions for PlotModel used in examples. + /// + public static class PlotModelUtilities + { + private const string XAXIS_KEY = "x"; + private const string YAXIS_KEY = "y"; + + /// + /// Lists all XYAxisSeries from the core library that are NOT reversible. + /// + private static readonly HashSet NonReversibleSeriesTypes = new HashSet + { + }; + + /// + /// Lists all Annotations that need axes and are NOT reversible. + /// + private static readonly HashSet NonReversibleDataSpaceAnnotationTypes = new HashSet + { + typeof(TileMapAnnotation), + }; + + /// + /// Lists all XYAxisSeries from the core library that are NOT transposable. + /// + private static readonly HashSet NonTransposableSeriesTypes = new HashSet + { + typeof(CandleStickAndVolumeSeries), + typeof(OldCandleStickSeries), + }; + + /// + /// Lists all Annotations that need axes and are NOT transposable. + /// + private static readonly HashSet NonTransposableDataSpaceAnnotationTypes = new HashSet + { + }; + + /// + /// Returns a value indicating whether a plot model is reversible. + /// + /// The plot model. + /// True if the plot model in reversible; false otherwise. + public static bool IsReversible(this PlotModel model) + { + return (model.Axes.Count > 0 || model.Series.Count > 0) + && model.Axes.All(a => a.Position != AxisPosition.None) + && model.Series.All(s => + { + var type = s.GetType(); + return s is XYAxisSeries + && type.GetTypeInfo().Assembly == typeof(PlotModel).GetTypeInfo().Assembly + && !NonReversibleSeriesTypes.Contains(type); + }) + && model.Annotations.All(a => + { + var type = a.GetType(); + return !NonReversibleDataSpaceAnnotationTypes.Contains(type); + }); + } + + /// + /// Returns a value indicating whether a plot model is transposable. + /// + /// The plot model. + /// True if the plot model in transposable; false otherwise. + public static bool IsTransposable(this PlotModel model) + { + return (model.Axes.Count > 0 || model.Series.Count > 0) + && model.Axes.All(a => a.Position != AxisPosition.None) + && model.Series.All(s => s is ITransposablePlotElement && !NonTransposableSeriesTypes.Contains(s.GetType())) + && model.Annotations.All(a => a is ITransposablePlotElement && !NonTransposableDataSpaceAnnotationTypes.Contains(a.GetType())); + } + + /// + /// Reverses the X Axis of a PlotModel. The given PlotModel is mutated and returned for convenience. + /// + /// The PlotModel. + /// The PlotModel with reversed X Axis. + public static PlotModel ReverseXAxis(this PlotModel model) + { + if (!string.IsNullOrEmpty(model.Title)) + { + model.Title += " (reversed X Axis)"; + } + + var foundXAxis = false; + foreach (var axis in model.Axes) + { + switch (axis.Position) + { + case AxisPosition.Bottom: + axis.StartPosition = 1 - axis.StartPosition; + axis.EndPosition = 1 - axis.EndPosition; + foundXAxis = true; + break; + case AxisPosition.Left: + case AxisPosition.Right: + case AxisPosition.Top: + case AxisPosition.None: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + if (!foundXAxis) + { + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, StartPosition = 1, EndPosition = 0}); + } + + return model; + } + + /// + /// Reverses the Y Axis of a PlotModel. The given PlotModel is mutated and returned for convenience. + /// + /// The PlotModel. + /// The PlotModel with reversed Y Axis. + public static PlotModel ReverseYAxis(this PlotModel model) + { + if (!string.IsNullOrEmpty(model.Title)) + { + model.Title += " (reversed Y Axis)"; + } + + var foundYAxis = false; + foreach (var axis in model.Axes) + { + switch (axis.Position) + { + case AxisPosition.Left: + axis.StartPosition = 1 - axis.StartPosition; + axis.EndPosition = 1 - axis.EndPosition; + foundYAxis = true; + break; + case AxisPosition.Bottom: + case AxisPosition.Right: + case AxisPosition.Top: + case AxisPosition.None: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + if (!foundYAxis) + { + model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, StartPosition = 1, EndPosition = 0}); + } + + return model; + } + + /// + /// Reverses X and Y Axes of a PlotModel. The given PlotModel is mutated and returned for convenience. + /// + /// The PlotModel. + /// The PlotModel with reversed X and Y Axis. + public static PlotModel ReverseXandYAxes(this PlotModel model) + { + var title = model.Title; + if (!string.IsNullOrEmpty(title)) + { + title += " (reversed both Axes)"; + } + + model = model.ReverseXAxis().ReverseYAxis(); + model.Title = title; + return model; + } + + /// + /// Reverses all axes of a PlotModel. The given PlotModel is mutated and returned for convenience. + /// + /// The PlotModel. + /// The PlotModel with reversed axes. + public static PlotModel ReverseAllAxes(this PlotModel model) + { + if (!string.IsNullOrEmpty(model.Title)) + { + model.Title += " (reversed all Axes)"; + } + + // Update plot to generate default axes etc. + ((IPlotModel)model).Update(false); + + foreach (var axis in model.Axes) + { + switch (axis.Position) + { + case AxisPosition.Left: + case AxisPosition.Bottom: + case AxisPosition.Right: + case AxisPosition.Top: + axis.StartPosition = 1 - axis.StartPosition; + axis.EndPosition = 1 - axis.EndPosition; + break; + case AxisPosition.None: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return model; + } + + /// + /// Transposes a PlotModel. The given PlotModel is mutated and returned for convenience. + /// + /// The PlotModel. + /// The transposed PlotModel. + public static PlotModel Transpose(this PlotModel model) + { + if (!string.IsNullOrEmpty(model.Title)) + { + model.Title += " (transposed)"; + } + + // Update plot to generate default axes etc. + ((IPlotModel)model).Update(false); + + foreach (var axis in model.Axes) + { + switch (axis.Position) + { + case AxisPosition.Bottom: + axis.Position = AxisPosition.Left; + break; + case AxisPosition.Left: + axis.Position = AxisPosition.Bottom; + break; + case AxisPosition.Right: + axis.Position = AxisPosition.Top; + break; + case AxisPosition.Top: + axis.Position = AxisPosition.Right; + break; + case AxisPosition.None: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + foreach (var annotation in model.Annotations) + { + if (annotation.XAxis != null && annotation.XAxisKey == null) + { + if (annotation.XAxis.Key == null) + { + annotation.XAxis.Key = XAXIS_KEY; + } + + annotation.XAxisKey = annotation.XAxis.Key; + } + + if (annotation.YAxis != null && annotation.YAxisKey == null) + { + if (annotation.YAxis.Key == null) + { + annotation.YAxis.Key = YAXIS_KEY; + } + + annotation.YAxisKey = annotation.YAxis.Key; + } + } + + foreach (var series in model.Series.OfType()) + { + if (series.XAxisKey == null) + { + if (series.XAxis == null) // this can happen if the series is invisible initially + { + series.XAxisKey = XAXIS_KEY; + } + else + { + if (series.XAxis.Key == null) + { + series.XAxis.Key = XAXIS_KEY; + } + + series.XAxisKey = series.XAxis.Key; + } + } + + if (series.YAxisKey == null) + { + if (series.YAxis == null) + { + series.YAxisKey = YAXIS_KEY; + } + else + { + if (series.YAxis.Key == null) + { + series.YAxis.Key = YAXIS_KEY; + } + + series.YAxisKey = series.YAxis.Key; + } + } + } + + return model; + } + } +} diff --git a/Source/Examples/ExampleLibrary/Utilities/Sun.cs b/Source/Examples/ExampleLibrary/Utilities/Sun.cs new file mode 100644 index 0000000..1c7241d --- /dev/null +++ b/Source/Examples/ExampleLibrary/Utilities/Sun.cs @@ -0,0 +1,227 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Calculation of sunrise/sunset +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleLibrary +{ + using System; + + /// + /// Calculation of sunrise/sunset + /// + /// http://williams.best.vwh.net/sunrise_sunset_algorithm.htm + /// based on code by Huysentruit Wouter, Fastload-Media.be + public static class Sun + { + private static double Deg2Rad(double angle) + { + return Math.PI * angle / 180.0; + } + + private static double Rad2Deg(double angle) + { + return 180.0 * angle / Math.PI; + } + + private static double FixValue(double value, double min, double max) + { + while (value < min) + { + value += max - min; + } + + while (value >= max) + { + value -= max - min; + } + + return value; + } + + public static DateTime Calculate(DateTime date, double latitude, double longitude, bool sunrise, Func utcToLocalTime, double zenith = 90.5) + { + // 1. first calculate the day of the year + int n = date.DayOfYear; + + // 2. convert the longitude to hour value and calculate an approximate time + double lngHour = longitude / 15.0; + + double t; + + if (sunrise) + { + t = n + ((6.0 - lngHour) / 24.0); + } + else + { + t = n + ((18.0 - lngHour) / 24.0); + } + + // 3. calculate the Sun's mean anomaly + double m = (0.9856 * t) - 3.289; + + // 4. calculate the Sun's true longitude + double l = m + (1.916 * Math.Sin(Deg2Rad(m))) + (0.020 * Math.Sin(Deg2Rad(2 * m))) + 282.634; + l = FixValue(l, 0, 360); + + // 5a. calculate the Sun's right ascension + double ra = Rad2Deg(Math.Atan(0.91764 * Math.Tan(Deg2Rad(l)))); + ra = FixValue(ra, 0, 360); + + // 5b. right ascension value needs to be in the same quadrant as L + double lquadrant = Math.Floor(l / 90.0) * 90.0; + double raquadrant = Math.Floor(ra / 90.0) * 90.0; + ra = ra + (lquadrant - raquadrant); + + // 5c. right ascension value needs to be converted into hours + ra = ra / 15.0; + + // 6. calculate the Sun's declination + double sinDec = 0.39782 * Math.Sin(Deg2Rad(l)); + double cosDec = Math.Cos(Math.Asin(sinDec)); + + // 7a. calculate the Sun's local hour angle + double cosH = (Math.Cos(Deg2Rad(zenith)) - (sinDec * Math.Sin(Deg2Rad(latitude)))) / + (cosDec * Math.Cos(Deg2Rad(latitude))); + + // 7b. finish calculating H and convert into hours + double h; + + if (sunrise) + { + h = 360.0 - Rad2Deg(Math.Acos(cosH)); + } + else + { + h = Rad2Deg(Math.Acos(cosH)); + } + + h = h / 15.0; + + // 8. calculate local mean time of rising/setting + double localMeanTime = h + ra - (0.06571 * t) - 6.622; + + // 9. adjust back to UTC + double utc = localMeanTime - lngHour; + + // 10. convert UT value to local time zone of latitude/longitude + date = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc); + var utctime = date.AddHours(utc); + var localTime = utcToLocalTime(utctime); + + utc = (localTime - date).TotalHours; + utc = FixValue(utc, 0, 24); + return date.AddHours(utc); + } + } + + /* + Sunrise/Sunset Algorithm + + Source: + Almanac for Computers, 1990 + published by Nautical Almanac Office + United States Naval Observatory + Washington, DC 20392 + + Inputs: + day, month, year: date of sunrise/sunset + latitude, longitude: location for sunrise/sunset + zenith: Sun's zenith for sunrise/sunset + offical = 90 degrees 50' + civil = 96 degrees + nautical = 102 degrees + astronomical = 108 degrees + + NOTE: longitude is positive for East and negative for West + NOTE: the algorithm assumes the use of a calculator with the + trig functions in "degree" (rather than "radian") mode. Most + programming languages assume radian arguments, requiring back + and forth convertions. The factor is 180/pi. So, for instance, + the equation RA = atan(0.91764 * tan(L)) would be coded as RA + = (180/pi)*atan(0.91764 * tan((pi/180)*L)) to give a degree + answer with a degree input for L. + + 1. first calculate the day of the year + + N1 = floor(275 * month / 9) + N2 = floor((month + 9) / 12) + N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3)) + N = N1 - (N2 * N3) + day - 30 + + 2. convert the longitude to hour value and calculate an approximate time + + lngHour = longitude / 15 + + if rising time is desired: + t = N + ((6 - lngHour) / 24) + if setting time is desired: + t = N + ((18 - lngHour) / 24) + + 3. calculate the Sun's mean anomaly + + M = (0.9856 * t) - 3.289 + + 4. calculate the Sun's true longitude + + L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634 + NOTE: L potentially needs to be adjusted into the range [0,360) by adding/subtracting 360 + + 5a. calculate the Sun's right ascension + + RA = atan(0.91764 * tan(L)) + NOTE: RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360 + + 5b. right ascension value needs to be in the same quadrant as L + + Lquadrant = (floor( L/90)) * 90 + RAquadrant = (floor(RA/90)) * 90 + RA = RA + (Lquadrant - RAquadrant) + + 5c. right ascension value needs to be converted into hours + + RA = RA / 15 + + 6. calculate the Sun's declination + + sinDec = 0.39782 * sin(L) + cosDec = cos(asin(sinDec)) + + 7a. calculate the Sun's local hour angle + + cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude)) + + if (cosH > 1) + the sun never rises on this location (on the specified date) + if (cosH < -1) + the sun never sets on this location (on the specified date) + + 7b. finish calculating H and convert into hours + + if if rising time is desired: + H = 360 - acos(cosH) + if setting time is desired: + H = acos(cosH) + + H = H / 15 + + 8. calculate local mean time of rising/setting + + T = H + RA - (0.06571 * t) - 6.622 + + 9. adjust back to UTC + + UT = T - lngHour + NOTE: UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24 + + 10. convert UT value to local time zone of latitude/longitude + + localT = UT + localOffset + + */ +} \ No newline at end of file diff --git a/Source/Examples/ImageSharp/Example1/Example1.csproj b/Source/Examples/ImageSharp/Example1/Example1.csproj new file mode 100644 index 0000000..fa7c424 --- /dev/null +++ b/Source/Examples/ImageSharp/Example1/Example1.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + + + + + + + diff --git a/Source/Examples/ImageSharp/Example1/Program.cs b/Source/Examples/ImageSharp/Example1/Program.cs new file mode 100644 index 0000000..2e3922e --- /dev/null +++ b/Source/Examples/ImageSharp/Example1/Program.cs @@ -0,0 +1,96 @@ +namespace Example1 +{ + using System; + using System.IO; + using System.Linq; + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.ImageSharp; + using OxyPlot.Series; + + class Program + { + static void Main(string[] args) + { + var outputToFile = "test-oxyplot-static-export-file"; + var outputExportStreamOOP = "test-oxyplot-export-stream"; + + var width = 1024; + var height = 768; + var resolutions = new[] { 72d, 96d, 182d }; + + var model = BuildPlotModel(); + + foreach (var resolution in resolutions) + { + // export to file using static methods + PngExporter.Export(model, $"{outputToFile}{resolution}.png", width, height, resolution); + + // export using the instance methods + using (var stream = new MemoryStream()) + { + var pngExporter = new PngExporter(width, height, resolution); + pngExporter.Export(model, stream); + System.IO.File.WriteAllBytes($"{outputExportStreamOOP}{resolution}.png", stream.ToArray()); + } + + model.Background = OxyColors.White; + + // export to file using static methods + JpegExporter.Export(model, $"{outputToFile}{resolution}.jpg", width, height, resolution); + + // export using the instance methods + using (var stream = new MemoryStream()) + { + var jpegExporter = new JpegExporter(width, height, resolution); + jpegExporter.Export(model, stream); + System.IO.File.WriteAllBytes($"{outputExportStreamOOP}{resolution}.jpg", stream.ToArray()); + } + } + } + + private static PlotModel BuildPlotModel() + { + var rand = new Random(21); + + var model = new PlotModel { Title = "Cake Type Popularity" }; + + var cakePopularity = Enumerable.Range(1, 5).Select(i => rand.NextDouble()).ToArray(); + var sum = cakePopularity.Sum(); + var barItems = cakePopularity.Select(cp => RandomBarItem(cp, sum)).ToArray(); + var barSeries = new BarSeries + { + ItemsSource = barItems, + LabelPlacement = LabelPlacement.Base, + LabelFormatString = "{0:.00}%" + }; + + model.Series.Add(barSeries); + + model.Axes.Add(new CategoryAxis + { + Position = AxisPosition.Left, + Key = "CakeAxis", + ItemsSource = new[] + { + "Apple cake", + "Baumkuchen", + "Bundt Cake", + "Chocolate cake", + "Carrot cake" + } + }); + + return model; + } + + private static BarItem RandomBarItem(double cp, double sum) + => new BarItem { Value = cp / sum * 100, Color = RandomColor() }; + + private static OxyColor RandomColor() + { + var r = new Random(); + return OxyColor.FromRgb((byte)r.Next(255), (byte)r.Next(255), (byte)r.Next(255)); + } + } +} diff --git a/Source/Examples/LINQPad/MyExtensions.FW40.linq b/Source/Examples/LINQPad/MyExtensions.FW40.linq new file mode 100644 index 0000000..627ca34 --- /dev/null +++ b/Source/Examples/LINQPad/MyExtensions.FW40.linq @@ -0,0 +1,33 @@ + + + <RuntimeDirectory>\System.Xaml.dll + <RuntimeDirectory>\WPF\WindowsBase.dll + <RuntimeDirectory>\WPF\PresentationCore.dll + <RuntimeDirectory>\WPF\PresentationFramework.dll + + System.Windows + System.Windows.Controls + System.Windows.Media + OxyPlot + OxyPlot.Wpf + + +void Main() +{ + var pm = new PlotModel("Sine curve"); + pm.Series.Add(new FunctionSeries(Math.Sin,0,20,200)); + pm.Show(); +} + +public static class MyExtensions +{ + public static void Show(this PlotModel model, double width = 800, double height = 500) { + var w = new Window() { Title = "OxyPlot.Wpf.PlotView : " + model.Title, Width = width, Height = height }; + var plot = new PlotView(); + plot.Model = model; + w.Content = plot; + w.Show(); + } +} + +// You can also define non-static classes, enums, etc. \ No newline at end of file diff --git a/Source/Examples/LINQPad/ReadMe.txt b/Source/Examples/LINQPad/ReadMe.txt new file mode 100644 index 0000000..d8e4340 --- /dev/null +++ b/Source/Examples/LINQPad/ReadMe.txt @@ -0,0 +1,8 @@ +Tested with LINQPad 4.38.07 (Beta, free edition) + +1. Build OxyPlot release + Tools/build.cmd +2. Start LINQPad +3. Set the plugins/extensions and queries folders to the "OxyPlot/Source/Examples/LINQPad" folder +4. Test the "My extensions" main example +5. Test the SimpleFunction/SimpleLinePlot queries diff --git a/Source/Examples/LINQPad/SimpleFunction.linq b/Source/Examples/LINQPad/SimpleFunction.linq new file mode 100644 index 0000000..9fae7af --- /dev/null +++ b/Source/Examples/LINQPad/SimpleFunction.linq @@ -0,0 +1,14 @@ + + OxyPlot + + +void Main() +{ + var pm = new PlotModel("Simple Function Plots") { PlotType = PlotType.Cartesian }; + + pm.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.1, "sin(x)")); + pm.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.1, "cos(x)")); + pm.Series.Add(new FunctionSeries(t => 5 * Math.Cos(t), t => 5 * Math.Sin(t), 0, 2 * Math.PI, 0.1, "5cos(t),5sin(t)")); + + pm.Show(); +} \ No newline at end of file diff --git a/Source/Examples/LINQPad/SimpleLinePlot.linq b/Source/Examples/LINQPad/SimpleLinePlot.linq new file mode 100644 index 0000000..2c5d832 --- /dev/null +++ b/Source/Examples/LINQPad/SimpleLinePlot.linq @@ -0,0 +1,18 @@ + + OxyPlot + + +void Main() +{ + var pm = new PlotModel("Simple Line Plot"); + + var lineSeries1 = new LineSeries("LineSeries1"); + + lineSeries1.Points.Add( new DataPoint (1,1)); + lineSeries1.Points.Add( new DataPoint (2,2)); + lineSeries1.Points.Add( new DataPoint (3,1.5)); + + pm.Series.Add(lineSeries1); + + pm.Show(); +} \ No newline at end of file diff --git a/Source/Examples/PerformanceTest/App.config b/Source/Examples/PerformanceTest/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/Source/Examples/PerformanceTest/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Source/Examples/PerformanceTest/EmptyRenderContext.cs b/Source/Examples/PerformanceTest/EmptyRenderContext.cs new file mode 100644 index 0000000..7a282d2 --- /dev/null +++ b/Source/Examples/PerformanceTest/EmptyRenderContext.cs @@ -0,0 +1,103 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Provides an empty that does nothing. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace PerformanceTest +{ + using System.Collections.Generic; + + using OxyPlot; + + /// + /// Provides an empty that does nothing. + /// + public class EmptyRenderContext : IRenderContext + { + /// + public bool RendersToScreen { get; set; } = true; + + /// + public void CleanUp() + { + } + + /// + public void DrawEllipse(OxyRect extents, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode) + { + } + + /// + public void DrawEllipses(IList extents, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode) + { + } + + /// + public void DrawImage(OxyImage source, double srcX, double srcY, double srcWidth, double srcHeight, double destX, double destY, double destWidth, double destHeight, double opacity, bool interpolate) + { + } + + /// + public void PushClip(OxyRect clippingRectangle) + { + } + + /// + public void PopClip() + { + } + + /// + public int ClipCount => 0; + + /// + public void DrawLine(IList points, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode, double[] dashArray = null, LineJoin lineJoin = LineJoin.Miter) + { + } + + /// + public void DrawLineSegments(IList points, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode, double[] dashArray = null, LineJoin lineJoin = LineJoin.Miter) + { + } + + /// + public void DrawPolygon(IList points, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode, double[] dashArray = null, LineJoin lineJoin = LineJoin.Miter) + { + } + + /// + public void DrawPolygons(IList> polygons, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode, double[] dashArray = null, LineJoin lineJoin = LineJoin.Miter) + { + } + + /// + public void DrawRectangle(OxyRect rectangle, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode) + { + } + + /// + public void DrawRectangles(IList rectangles, OxyColor fill, OxyColor stroke, double thickness, EdgeRenderingMode edgeRenderingMode) + { + } + + /// + public void DrawText(ScreenPoint p, string text, OxyColor fill, string fontFamily = null, double fontSize = 10, double fontWeight = 400, double rotation = 0, HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left, VerticalAlignment verticalAlignment = VerticalAlignment.Top, OxySize? maxSize = null) + { + } + + /// + public OxySize MeasureText(string text, string fontFamily = null, double fontSize = 10, double fontWeight = 500) + { + return OxySize.Empty; + } + + /// + public void SetToolTip(string text) + { + } + } +} diff --git a/Source/Examples/PerformanceTest/PerformanceTest.csproj b/Source/Examples/PerformanceTest/PerformanceTest.csproj new file mode 100644 index 0000000..2d82684 --- /dev/null +++ b/Source/Examples/PerformanceTest/PerformanceTest.csproj @@ -0,0 +1,11 @@ + + + net462;net6.0-windows;net7.0-windows + Exe + + + + + + + diff --git a/Source/Examples/PerformanceTest/Program.cs b/Source/Examples/PerformanceTest/Program.cs new file mode 100644 index 0000000..f874399 --- /dev/null +++ b/Source/Examples/PerformanceTest/Program.cs @@ -0,0 +1,148 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// A performance test program. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace PerformanceTest +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + + using OxyPlot; + using OxyPlot.Series; + + /// + /// A performance test program. + /// + /// + /// Build with the Release configuration. + /// To be used with a profiler or as a standalone program (remember to run outside the Visual Studio IDE). + /// + public class Program + { + /// + /// The program entry point. + /// + public static void Main() + { + var testModels = new Dictionary + { + { "LineSeries with 100000 points", CreateModel(100000) }, + { "LineSeries with 100000 points in ItemsSource", CreateModel2(100000) } + }; + + foreach (var kvp in testModels) + { + Console.WriteLine(kvp.Key); + TestModelUpdate(kvp.Value); + TestModelRender(kvp.Value); + Console.WriteLine(); + } + + Console.WriteLine("DrawReducedLine test:"); + var t0 = TestDrawReducedLine(10000, 1000, false); + var t1 = TestDrawReducedLine(10000, 1000, true); + Console.WriteLine("{0:P1}", (t0 - t1) / t0); + Console.ReadKey(); + } + + public static double TestModelUpdate(PlotModel model, int m = 1000) + { + var stopwatch = Stopwatch.StartNew(); + for (int i = 0; i < m; i++) + { + ((IPlotModel)model).Update(true); + } + + stopwatch.Stop(); + Console.WriteLine("Update: {0}", (double)stopwatch.ElapsedMilliseconds); + return stopwatch.ElapsedMilliseconds; + } + + public static double TestModelRender(PlotModel model, int m = 100) + { + var rc = new EmptyRenderContext(); + var stopwatch = Stopwatch.StartNew(); + for (int i = 0; i < m; i++) + { + ((IPlotModel)model).Render(rc, new OxyRect(0, 0, 800, 600)); + } + + stopwatch.Stop(); + Console.WriteLine("Render: {0}", (double)stopwatch.ElapsedMilliseconds); + return stopwatch.ElapsedMilliseconds; + } + + private static PlotModel CreateModel(int n) + { + var model = new PlotModel(); + var series = new LineSeries(); + for (int i = 0; i < n; i++) + { + series.Points.Add(new DataPoint(i, Math.Sin(i))); + } + + model.Series.Add(series); + ((IPlotModel)model).Update(true); + return model; + } + + private static PlotModel CreateModel2(int n) + { + var points = new List(); + for (int i = 0; i < n; i++) + { + points.Add(new DataPoint(i, Math.Sin(i))); + } + + var model = new PlotModel(); + var series = new LineSeries(); + series.ItemsSource = points; + + model.Series.Add(series); + ((IPlotModel)model).Update(true); + return model; + } + + /// + /// Tests the method. + /// + /// The number of points. + /// The number of repetitions. + /// true to use an output buffer. + /// The elapsed time in milliseconds. + public static double TestDrawReducedLine(int n, int m, bool useOutputBuffer) + { + var points = new ScreenPoint[n]; + for (int i = 0; i < n; i++) + { + points[i] = new ScreenPoint((double)i / n, Math.Sin(40d * i / n)); + } + + var rc = new EmptyRenderContext(); + var outputBuffer = useOutputBuffer ? new List(n) : null; + var stopwatch = Stopwatch.StartNew(); + for (int i = 0; i < m; i++) + { + rc.DrawReducedLine( + points, + 1, + OxyColors.Black, + 1, + EdgeRenderingMode.Automatic, + null, + LineJoin.Miter, + outputBuffer); + } + + stopwatch.Stop(); + Console.WriteLine((double)stopwatch.ElapsedMilliseconds); + return stopwatch.ElapsedMilliseconds; + } + } +} diff --git a/Source/Examples/WPF/ExampleBrowser/App.xaml b/Source/Examples/WPF/ExampleBrowser/App.xaml new file mode 100644 index 0000000..f26d13e --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Source/Examples/WPF/ExampleBrowser/App.xaml.cs b/Source/Examples/WPF/ExampleBrowser/App.xaml.cs new file mode 100644 index 0000000..0d8b056 --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/App.xaml.cs @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Interaction logic for App.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Windows; + +namespace ExampleBrowser +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/ExampleBrowser/ExampleBrowser.WPF.csproj b/Source/Examples/WPF/ExampleBrowser/ExampleBrowser.WPF.csproj new file mode 100644 index 0000000..898999f --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/ExampleBrowser.WPF.csproj @@ -0,0 +1,17 @@ + + + net462;net6.0-windows;net7.0-windows + true + WinExe + app.manifest + + + + + + + + + + + diff --git a/Source/Examples/WPF/ExampleBrowser/MainWindow.xaml b/Source/Examples/WPF/ExampleBrowser/MainWindow.xaml new file mode 100644 index 0000000..883fea0 --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/MainWindow.xaml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Examples/WPF/ExampleBrowser/MainWindow.xaml.cs b/Source/Examples/WPF/ExampleBrowser/MainWindow.xaml.cs new file mode 100644 index 0000000..85eb8c3 --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/MainWindow.xaml.cs @@ -0,0 +1,34 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Interaction logic for MainWindow.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleBrowser +{ + using Microsoft.Win32; + using System.Windows; + + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + this.InitializeComponent(); + SystemEvents.DisplaySettingsChanged += this.SystemEvents_DisplaySettingsChanged; + } + + private void SystemEvents_DisplaySettingsChanged(object sender, System.EventArgs e) + { + (this.DataContext as MainWindowViewModel)?.ActiveModel?.PlotView?.InvalidatePlot(false); + } + } +} diff --git a/Source/Examples/WPF/ExampleBrowser/MainWindowViewModel.cs b/Source/Examples/WPF/ExampleBrowser/MainWindowViewModel.cs new file mode 100644 index 0000000..e086aad --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/MainWindowViewModel.cs @@ -0,0 +1,165 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleBrowser +{ + using ExampleLibrary; + using OxyPlot; + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Windows.Data; + + public class MainWindowViewModel : INotifyPropertyChanged + { + private bool _CanTranspose; + private bool _CanReverse; + private string _Code; + private Renderer _Renderer; + private PlotModel _PlotModel; + private bool _Transposed; + private bool _Reversed; + private IEnumerable examples; + private ExampleInfo selectedExample; + + public MainWindowViewModel() + { + this.Examples = ExampleLibrary.Examples.GetList(); + this.ExamplesView = CollectionViewSource.GetDefaultView(this.Examples.OrderBy(e => e.Category)); + this.ExamplesView.GroupDescriptions.Add(new PropertyGroupDescription("Category")); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public PlotModel ActiveModel => this.CanvasModel ?? this.SkiaModel; + + public bool CanTranspose + { + get => this._CanTranspose; + private set + { + this._CanTranspose = value; + this.RaisePropertyChanged(nameof(this.CanTranspose)); + } + } + + public bool CanReverse + { + get => this._CanReverse; + private set + { + this._CanReverse = value; + this.RaisePropertyChanged(nameof(this.CanReverse)); + } + } + + public PlotModel CanvasModel => this.Renderer == Renderer.Canvas ? this._PlotModel : null; + + public string Code + { + get => this._Code; + set + { + this._Code = value; + this.RaisePropertyChanged(nameof(this.Code)); + } + } + + public IEnumerable Examples + { + get => this.examples; + set + { + this.examples = value; + this.RaisePropertyChanged(nameof(this.Examples)); + } + } + + public ICollectionView ExamplesView { get; set; } + + public Renderer Renderer + { + get => this._Renderer; + set + { + this._Renderer = value; + this.CoerceRenderer(); + this.RaisePropertyChanged(nameof(this.Renderer)); + } + } + + private void CoerceRenderer() + { + ((IPlotModel)this._PlotModel)?.AttachPlotView(null); + this.RaisePropertyChanged(nameof(this.SkiaModel)); + this.RaisePropertyChanged(nameof(this.CanvasXamlModel)); + this.RaisePropertyChanged(nameof(this.CanvasModel)); + } + + public IEnumerable Renderers => Enum.GetValues(typeof(Renderer)).Cast(); + + public ExampleInfo SelectedExample + { + get => this.selectedExample; + set + { + this.selectedExample = value; + this.CoerceSelectedExample(); + this.RaisePropertyChanged(nameof(this.SelectedExample)); + } + } + + public PlotModel SkiaModel => this.Renderer == Renderer.SkiaSharp ? this._PlotModel : null; + + public PlotModel CanvasXamlModel => this.Renderer == Renderer.Canvas_XAML ? this._PlotModel : null; + + public bool Transposed + { + get => this._Transposed; + set + { + this._Transposed = value; + this.UpdatePlotModel(); + this.RaisePropertyChanged(nameof(this.Transposed)); + } + } + + public bool Reversed + { + get => this._Reversed; + set + { + this._Reversed = value; + this.UpdatePlotModel(); + this.RaisePropertyChanged(nameof(this.Reversed)); + } + } + + protected void RaisePropertyChanged(string property) + { + this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property)); + } + + private void CoerceSelectedExample() + { + this.CanTranspose = this.SelectedExample?.IsTransposable == true; + this.CanReverse = this.SelectedExample?.IsReversible == true; + this.UpdatePlotModel(); + } + + private void UpdatePlotModel() + { + var flags = ExampleInfo.PrepareFlags( + this.CanTranspose && this.Transposed, + this.CanReverse && this.Reversed); + + this._PlotModel = this.SelectedExample?.GetModel(flags); + this.Code = this.SelectedExample?.GetCode(flags); + this.CoerceRenderer(); + } + } +} diff --git a/Source/Examples/WPF/ExampleBrowser/NotNullVisibilityConverter.cs b/Source/Examples/WPF/ExampleBrowser/NotNullVisibilityConverter.cs new file mode 100644 index 0000000..db5a1d0 --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/NotNullVisibilityConverter.cs @@ -0,0 +1,28 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleBrowser +{ + using System; + using System.Globalization; + using System.Windows; + using System.Windows.Data; + + public sealed class NotNullVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value == null + ? Visibility.Collapsed + : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new InvalidOperationException(); + } + } +} diff --git a/Source/Examples/WPF/ExampleBrowser/Properties/AssemblyInfo.cs b/Source/Examples/WPF/ExampleBrowser/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b22432b --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +using System.Windows; + +[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] diff --git a/Source/Examples/WPF/ExampleBrowser/Renderer.cs b/Source/Examples/WPF/ExampleBrowser/Renderer.cs new file mode 100644 index 0000000..26eaa2b --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/Renderer.cs @@ -0,0 +1,15 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleBrowser +{ + public enum Renderer + { + Canvas, + Canvas_XAML, + SkiaSharp + } +} diff --git a/Source/Examples/WPF/ExampleBrowser/XamlPlotView.cs b/Source/Examples/WPF/ExampleBrowser/XamlPlotView.cs new file mode 100644 index 0000000..f5c8bff --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/XamlPlotView.cs @@ -0,0 +1,22 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ExampleBrowser +{ + using OxyPlot; + using OxyPlot.Wpf; + + /// + /// Represents a PlotView which uses the XamlRenderContext for rendering. + /// + public class XamlPlotView : PlotView + { + protected override IRenderContext CreateRenderContext() + { + return new XamlRenderContext(this.Canvas); + } + } +} diff --git a/Source/Examples/WPF/ExampleBrowser/app.manifest b/Source/Examples/WPF/ExampleBrowser/app.manifest new file mode 100644 index 0000000..fed6c31 --- /dev/null +++ b/Source/Examples/WPF/ExampleBrowser/app.manifest @@ -0,0 +1,12 @@ + + + + + + + PerMonitor + true + + + + diff --git a/Source/Examples/WPF/SimpleDemo/App.xaml b/Source/Examples/WPF/SimpleDemo/App.xaml new file mode 100644 index 0000000..123ebf7 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Source/Examples/WPF/SimpleDemo/App.xaml.cs b/Source/Examples/WPF/SimpleDemo/App.xaml.cs new file mode 100644 index 0000000..0626832 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/App.xaml.cs @@ -0,0 +1,25 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Interaction logic for App.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace SimpleDemo +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/SimpleDemo/MainViewModel.cs b/Source/Examples/WPF/SimpleDemo/MainViewModel.cs new file mode 100644 index 0000000..0551a87 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/MainViewModel.cs @@ -0,0 +1,59 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents the view-model for the main window. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace SimpleDemo +{ + using OxyPlot; + using OxyPlot.Series; + + /// + /// Represents the view-model for the main window. + /// + public class MainViewModel + { + /// + /// Initializes a new instance of the class. + /// + public MainViewModel() + { + // Create the plot model + var tmp = new PlotModel { Title = "Simple example", Subtitle = "using OxyPlot" }; + + // Create two line series (markers are hidden by default) + var series1 = new LineSeries { Title = "Series 1", MarkerType = MarkerType.Circle }; + series1.Points.Add(new DataPoint(0, 0)); + series1.Points.Add(new DataPoint(10, 18)); + series1.Points.Add(new DataPoint(20, 12)); + series1.Points.Add(new DataPoint(30, 8)); + series1.Points.Add(new DataPoint(40, 15)); + + var series2 = new LineSeries { Title = "Series 2", MarkerType = MarkerType.Square }; + series2.Points.Add(new DataPoint(0, 4)); + series2.Points.Add(new DataPoint(10, 12)); + series2.Points.Add(new DataPoint(20, 16)); + series2.Points.Add(new DataPoint(30, 25)); + series2.Points.Add(new DataPoint(40, 5)); + + + // Add the series to the plot model + tmp.Series.Add(series1); + tmp.Series.Add(series2); + + // Axes are created automatically if they are not defined + + // Set the Model property, the INotifyPropertyChanged event will make the WPF Plot control update its content + this.Model = tmp; + } + + /// + /// Gets the plot model. + /// + public PlotModel Model { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/SimpleDemo/MainWindow.xaml b/Source/Examples/WPF/SimpleDemo/MainWindow.xaml new file mode 100644 index 0000000..6323731 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/MainWindow.xaml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/Source/Examples/WPF/SimpleDemo/MainWindow.xaml.cs b/Source/Examples/WPF/SimpleDemo/MainWindow.xaml.cs new file mode 100644 index 0000000..146c888 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/MainWindow.xaml.cs @@ -0,0 +1,25 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Interaction logic for MainWindow.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace SimpleDemo +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow + { + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + this.InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/SimpleDemo/Properties/AssemblyInfo.cs b/Source/Examples/WPF/SimpleDemo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b22432b --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +using System.Windows; + +[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] diff --git a/Source/Examples/WPF/SimpleDemo/SimpleDemo.csproj b/Source/Examples/WPF/SimpleDemo/SimpleDemo.csproj new file mode 100644 index 0000000..04794d8 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/SimpleDemo.csproj @@ -0,0 +1,11 @@ + + + net6.0-windows + true + WinExe + + + + + + diff --git a/Source/Examples/WPF/SimpleDemo/app.config b/Source/Examples/WPF/SimpleDemo/app.config new file mode 100644 index 0000000..de82893 --- /dev/null +++ b/Source/Examples/WPF/SimpleDemo/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Source/Examples/WPF/WpfExamples/App.xaml b/Source/Examples/WPF/WpfExamples/App.xaml new file mode 100644 index 0000000..260b6d5 --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Source/Examples/WPF/WpfExamples/App.xaml.cs b/Source/Examples/WPF/WpfExamples/App.xaml.cs new file mode 100644 index 0000000..b33d063 --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/App.xaml.cs @@ -0,0 +1,25 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Interaction logic for App.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace WpfExamples +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/WpfExamples/BitmapTools.cs b/Source/Examples/WPF/WpfExamples/BitmapTools.cs new file mode 100644 index 0000000..fcc12ac --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/BitmapTools.cs @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace WpfExamples +{ + using System.Drawing; + using System.Drawing.Drawing2D; + + public static class BitmapTools + { + public static Bitmap Resize(Bitmap bitmap, int newWidth, int newHeight) + { + var resizedBitmap = new Bitmap(newWidth, newHeight); + var g = Graphics.FromImage(resizedBitmap); + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.DrawImage(bitmap, 0, 0, newWidth, newHeight); + g.Dispose(); + return resizedBitmap; + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/WpfExamples/DelegateCommand.cs b/Source/Examples/WPF/WpfExamples/DelegateCommand.cs new file mode 100644 index 0000000..52d85e3 --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/DelegateCommand.cs @@ -0,0 +1,104 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Represents a delegate command. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace WpfExamples +{ + using System; + using System.Windows.Input; + + /// + /// Represents a delegate command. + /// + public class DelegateCommand : ICommand + { + /// + /// The can execute. + /// + private readonly Func canExecute; + + /// + /// The execute. + /// + private readonly Action execute; + + /// + /// Initializes a new instance of the class. + /// + /// The execute. + public DelegateCommand(Action execute) + : this(execute, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The execute. + /// The can execute. + public DelegateCommand(Action execute, Func canExecute) + { + if (execute == null) + { + throw new ArgumentNullException("execute"); + } + + this.execute = execute; + this.canExecute = canExecute; + } + + /// + /// Occurs when changes occur that affect whether or not the command should execute. + /// + public event EventHandler CanExecuteChanged + { + add + { + if (this.canExecute != null) + { + CommandManager.RequerySuggested += value; + } + } + + remove + { + if (this.canExecute != null) + { + CommandManager.RequerySuggested -= value; + } + } + } + + /// + /// Defines the method that determines whether the command can execute in its current state. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + /// true if this command can be executed; otherwise, false. + public bool CanExecute(object parameter) + { + return this.canExecute == null ? true : this.canExecute(); + } + + /// + /// Defines the method to be called when the command is invoked. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + public void Execute(object parameter) + { + this.execute(); + } + + /// + /// Raises the can execute changed. + /// + public void RaiseCanExecuteChanged() + { + CommandManager.InvalidateRequerySuggested(); + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/WpfExamples/Example.cs b/Source/Examples/WPF/WpfExamples/Example.cs new file mode 100644 index 0000000..3fef53d --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/Example.cs @@ -0,0 +1,56 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace WpfExamples +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + public class Example + { + public Example(Type mainWindowType, string title = null, string description = null) + { + this.MainWindowType = mainWindowType; + this.Title = title ?? mainWindowType.Namespace; + this.Description = description; + try + { + this.Thumbnail = new BitmapImage(new Uri("pack://application:,,,/Images/" + this.ThumbnailFileName)); + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + + public string Title { get; private set; } + public string Description { get; set; } + private Type MainWindowType { get; set; } + + public ImageSource Thumbnail { get; set; } + + public string ThumbnailFileName + { + get + { + return this.MainWindowType.Namespace + ".png"; + } + } + + public override string ToString() + { + return this.Title; + } + + public Window Create() + { + return Activator.CreateInstance(this.MainWindowType) as Window; + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/WpfExamples/ExampleAttribute.cs b/Source/Examples/WPF/WpfExamples/ExampleAttribute.cs new file mode 100644 index 0000000..dab18c7 --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/ExampleAttribute.cs @@ -0,0 +1,28 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace WpfExamples +{ + using System; + + public class ExampleAttribute : Attribute + { + public ExampleAttribute(string description) + : this(null, description) + { + } + + public ExampleAttribute(string title, string description) + { + this.Title = title; + this.Description = description; + } + + public string Title { get; private set; } + + public string Description { get; private set; } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/WpfExamples/Examples/AlignedAxesDemo/MainWindow.xaml b/Source/Examples/WPF/WpfExamples/Examples/AlignedAxesDemo/MainWindow.xaml new file mode 100644 index 0000000..8992476 --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/Examples/AlignedAxesDemo/MainWindow.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/Source/Examples/WPF/WpfExamples/Examples/AlignedAxesDemo/MainWindow.xaml.cs b/Source/Examples/WPF/WpfExamples/Examples/AlignedAxesDemo/MainWindow.xaml.cs new file mode 100644 index 0000000..fa16f65 --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/Examples/AlignedAxesDemo/MainWindow.xaml.cs @@ -0,0 +1,55 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 OxyPlot contributors +// +// +// Interaction logic for MainWindow.xaml +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace AlignedAxesDemo +{ + using System; + + using OxyPlot; + using OxyPlot.Axes; + using OxyPlot.Series; + + using WpfExamples; + + /// + /// Interaction logic for MainWindow.xaml + /// + [Example("Aligning plot margins from desired axis widths.")] + public partial class MainWindow + { + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + this.InitializeComponent(); + this.Model0 = CreatePlotModel(0, 10); + this.Model1 = CreatePlotModel(0, 1e8); + + // TODO: align the vertical axis size without setting PlotMargins + this.Model0.PlotMargins = this.Model1.PlotMargins = new OxyThickness(70, 40, 20, 20); + + this.DataContext = this; + } + + public PlotModel Model0 { get; private set; } + + public PlotModel Model1 { get; private set; } + + private static PlotModel CreatePlotModel(double min, double max) + { + var model = new PlotModel(); + var verticalAxis = new LinearAxis { Position = AxisPosition.Left, Minimum = min, Maximum = max }; + model.Axes.Add(verticalAxis); + model.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom }); + model.Series.Add(new FunctionSeries(x => Math.Sin(x * Math.PI * 4) * Math.Sin(x * Math.PI * 4) * Math.Sqrt(x) * max, 0, 1, 1000)); + return model; + } + } +} \ No newline at end of file diff --git a/Source/Examples/WPF/WpfExamples/Examples/AnimationsDemo/Controls/AnimationSettingsControl.xaml b/Source/Examples/WPF/WpfExamples/Examples/AnimationsDemo/Controls/AnimationSettingsControl.xaml new file mode 100644 index 0000000..86b1e3f --- /dev/null +++ b/Source/Examples/WPF/WpfExamples/Examples/AnimationsDemo/Controls/AnimationSettingsControl.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + +