diff --git a/.mplstyle b/.mplstyle new file mode 100644 index 0000000..59e4d9f --- /dev/null +++ b/.mplstyle @@ -0,0 +1,864 @@ +# Overall figure +axes.facecolor: white # axes background color +axes.edgecolor: black # axes edge color +axes.linewidth: 0.8 # edge line width + +axes.grid: True # display grid or not +axes.grid.axis: both # which axis the grid should apply to +axes.grid.which: both # grid lines at {major, minor, both} ticks + +grid.linewidth: 0.2 +grid.color: black + +xtick.top:True +ytick.right:True + +#### MATPLOTLIBRC FORMAT + +## DO NOT EDIT THIS FILE, MAKE A COPY FIRST +## +## This is a sample Matplotlib configuration file - you can find a copy +## of it on your system in site-packages/matplotlib/mpl-data/matplotlibrc +## (relative to your Python installation location). +## DO NOT EDIT IT! +## +## If you wish to change your default style, copy this file to one of the +## following locations: +## Unix/Linux: +## $HOME/.config/matplotlib/matplotlibrc OR +## $XDG_CONFIG_HOME/matplotlib/matplotlibrc (if $XDG_CONFIG_HOME is set) +## Other platforms: +## $HOME/.matplotlib/matplotlibrc +## and edit that copy. +## +## See https://matplotlib.org/stable/users/explain/customizing.html#customizing-with-matplotlibrc-files +## for more details on the paths which are checked for the configuration file. +## +## Blank lines, or lines starting with a comment symbol, are ignored, as are +## trailing comments. Other lines must have the format: +## key: val # optional comment +## +## Formatting: Use PEP8-like style (as enforced in the rest of the codebase). +## All lines start with an additional '#', so that removing all leading '#'s +## yields a valid style file. +## +## Colors: for the color values below, you can either use +## - a Matplotlib color string, such as r, k, or b +## - an RGB tuple, such as (1.0, 0.5, 0.0) +## - a double-quoted hex string, such as "#ff00ff". +## The unquoted string ff00ff is also supported for backward +## compatibility, but is discouraged. +## - a scalar grayscale intensity such as 0.75 +## - a legal html color name, e.g., red, blue, darkslategray +## +## String values may optionally be enclosed in double quotes, which allows +## using the comment character # in the string. +## +## This file (and other style files) must be encoded as utf-8. +## +## Matplotlib configuration are currently divided into following parts: +## - BACKENDS +## - LINES +## - PATCHES +## - HATCHES +## - BOXPLOT +## - FONT +## - TEXT +## - LaTeX +## - AXES +## - DATES +## - TICKS +## - GRIDS +## - LEGEND +## - FIGURE +## - IMAGES +## - CONTOUR PLOTS +## - ERRORBAR PLOTS +## - HISTOGRAM PLOTS +## - SCATTER PLOTS +## - AGG RENDERING +## - PATHS +## - SAVING FIGURES +## - INTERACTIVE KEYMAPS +## - ANIMATION + +##### CONFIGURATION BEGINS HERE + + +## *************************************************************************** +## * BACKENDS * +## *************************************************************************** +## The default backend. If you omit this parameter, the first working +## backend from the following list is used: +## MacOSX QtAgg Gtk4Agg Gtk3Agg TkAgg WxAgg Agg +## Other choices include: +## QtCairo GTK4Cairo GTK3Cairo TkCairo WxCairo Cairo +## Qt5Agg Qt5Cairo Wx # deprecated. +## PS PDF SVG Template +## You can also deploy your own backend outside of Matplotlib by referring to +## the module name (which must be in the PYTHONPATH) as 'module://my_backend'. +##backend: Agg + +## The port to use for the web server in the WebAgg backend. +#webagg.port: 8988 + +## The address on which the WebAgg web server should be reachable +#webagg.address: 127.0.0.1 + +## If webagg.port is unavailable, a number of other random ports will +## be tried until one that is available is found. +#webagg.port_retries: 50 + +## When True, open the web browser to the plot that is shown +#webagg.open_in_browser: True + +## If you are running pyplot inside a GUI and your backend choice +## conflicts, we will automatically try to find a compatible one for +## you if backend_fallback is True +#backend_fallback: True + +#interactive: False +#figure.hooks: # list of dotted.module.name:dotted.callable.name +#toolbar: toolbar2 # {None, toolbar2, toolmanager} +#timezone: UTC # a pytz timezone string, e.g., US/Central or Europe/Paris + + +## *************************************************************************** +## * LINES * +## *************************************************************************** +## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.lines +## for more information on line properties. +#lines.linewidth: 1.5 # line width in points +#lines.linestyle: - # solid line +#lines.color: C0 # has no affect on plot(); see axes.prop_cycle +#lines.marker: None # the default marker +#lines.markerfacecolor: auto # the default marker face color +#lines.markeredgecolor: auto # the default marker edge color +#lines.markeredgewidth: 1.0 # the line width around the marker symbol +#lines.markersize: 6 # marker size, in points +#lines.dash_joinstyle: round # {miter, round, bevel} +#lines.dash_capstyle: butt # {butt, round, projecting} +#lines.solid_joinstyle: round # {miter, round, bevel} +#lines.solid_capstyle: projecting # {butt, round, projecting} +#lines.antialiased: True # render lines in antialiased (no jaggies) + +## The three standard dash patterns. These are scaled by the linewidth. +#lines.dashed_pattern: 3.7, 1.6 +#lines.dashdot_pattern: 6.4, 1.6, 1, 1.6 +#lines.dotted_pattern: 1, 1.65 +#lines.scale_dashes: True + +#markers.fillstyle: full # {full, left, right, bottom, top, none} + +#pcolor.shading: auto +#pcolormesh.snap: True # Whether to snap the mesh to pixel boundaries. This is + # provided solely to allow old test images to remain + # unchanged. Set to False to obtain the previous behavior. + +## *************************************************************************** +## * PATCHES * +## *************************************************************************** +## Patches are graphical objects that fill 2D space, like polygons or circles. +## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.patches +## for more information on patch properties. +#patch.linewidth: 1.0 # edge width in points. +#patch.facecolor: C0 +#patch.edgecolor: black # By default, Patches and Collections do not draw edges. + # This value is only used if facecolor is "none" + # (an Artist without facecolor and edgecolor would be + # invisible) or if patch.force_edgecolor is True. +#patch.force_edgecolor: False # By default, Patches and Collections do not draw edges. + # Set this to True to draw edges with patch.edgedcolor + # as the default edgecolor. + # This is mainly relevant for styles. +#patch.antialiased: True # render patches in antialiased (no jaggies) + + +## *************************************************************************** +## * HATCHES * +## *************************************************************************** +#hatch.color: edge +#hatch.linewidth: 1.0 + + +## *************************************************************************** +## * BOXPLOT * +## *************************************************************************** +#boxplot.notch: False +#boxplot.vertical: True +#boxplot.whiskers: 1.5 +#boxplot.bootstrap: None +#boxplot.patchartist: False +#boxplot.showmeans: False +#boxplot.showcaps: True +#boxplot.showbox: True +#boxplot.showfliers: True +#boxplot.meanline: False + +#boxplot.flierprops.color: black +#boxplot.flierprops.marker: o +#boxplot.flierprops.markerfacecolor: none +#boxplot.flierprops.markeredgecolor: black +#boxplot.flierprops.markeredgewidth: 1.0 +#boxplot.flierprops.markersize: 6 +#boxplot.flierprops.linestyle: none +#boxplot.flierprops.linewidth: 1.0 + +#boxplot.boxprops.color: black +#boxplot.boxprops.linewidth: 1.0 +#boxplot.boxprops.linestyle: - + +#boxplot.whiskerprops.color: black +#boxplot.whiskerprops.linewidth: 1.0 +#boxplot.whiskerprops.linestyle: - + +#boxplot.capprops.color: black +#boxplot.capprops.linewidth: 1.0 +#boxplot.capprops.linestyle: - + +#boxplot.medianprops.color: C1 +#boxplot.medianprops.linewidth: 1.0 +#boxplot.medianprops.linestyle: - + +#boxplot.meanprops.color: C2 +#boxplot.meanprops.marker: ^ +#boxplot.meanprops.markerfacecolor: C2 +#boxplot.meanprops.markeredgecolor: C2 +#boxplot.meanprops.markersize: 6 +#boxplot.meanprops.linestyle: -- +#boxplot.meanprops.linewidth: 1.0 + + +## *************************************************************************** +## * FONT * +## *************************************************************************** +## The font properties used by `text.Text`. +## See https://matplotlib.org/stable/api/font_manager_api.html for more information +## on font properties. The 6 font properties used for font matching are +## given below with their default values. +## +## The font.family property can take either a single or multiple entries of any +## combination of concrete font names (not supported when rendering text with +## usetex) or the following five generic values: +## - 'serif' (e.g., Times), +## - 'sans-serif' (e.g., Helvetica), +## - 'cursive' (e.g., Zapf-Chancery), +## - 'fantasy' (e.g., Western), and +## - 'monospace' (e.g., Courier). +## Each of these values has a corresponding default list of font names +## (font.serif, etc.); the first available font in the list is used. Note that +## for font.serif, font.sans-serif, and font.monospace, the first element of +## the list (a DejaVu font) will always be used because DejaVu is shipped with +## Matplotlib and is thus guaranteed to be available; the other entries are +## left as examples of other possible values. +## +## The font.style property has three values: normal (or roman), italic +## or oblique. The oblique style will be used for italic, if it is not +## present. +## +## The font.variant property has two values: normal or small-caps. For +## TrueType fonts, which are scalable fonts, small-caps is equivalent +## to using a font size of 'small', or about 83 % of the current font +## size. +## +## The font.weight property has effectively 13 values: normal, bold, +## bolder, lighter, 100, 200, 300, ..., 900. Normal is the same as +## 400, and bold is 700. bolder and lighter are relative values with +## respect to the current weight. +## +## The font.stretch property has 11 values: ultra-condensed, +## extra-condensed, condensed, semi-condensed, normal, semi-expanded, +## expanded, extra-expanded, ultra-expanded, wider, and narrower. This +## property is not currently implemented. +## +## The font.size property is the default font size for text, given in points. +## 10 pt is the standard value. +## +## Note that font.size controls default text sizes. To configure +## special text sizes tick labels, axes, labels, title, etc., see the rc +## settings for axes and ticks. Special text sizes can be defined +## relative to font.size, using the following values: xx-small, x-small, +## small, medium, large, x-large, xx-large + +#font.family: sans-serif +#font.style: normal +#font.variant: normal +#font.weight: normal +#font.stretch: normal +#font.size: 10.0 + +#font.serif: DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif +#font.sans-serif: DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif +#font.cursive: Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, Comic Neue, Comic Sans MS, cursive +#font.fantasy: Chicago, Charcoal, Impact, Western, xkcd script, fantasy +#font.monospace: DejaVu Sans Mono, Bitstream Vera Sans Mono, Computer Modern Typewriter, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace + +## If font.enable_last_resort is True, then Unicode Consortium's Last Resort +## font will be appended to all font selections. This ensures that there will +## always be a glyph displayed. +#font.enable_last_resort: true + + +## *************************************************************************** +## * TEXT * +## *************************************************************************** +## The text properties used by `text.Text`. +## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.text +## for more information on text properties +#text.color: black + +## The language of the text in a format accepted by libraqm, namely `a BCP47 language +## code `_. If None, then no +## particular language will be implied, and default font settings will be used. +#text.language: None + +## FreeType hinting flag ("foo" corresponds to FT_LOAD_FOO); may be one of the +## following (Proprietary Matplotlib-specific synonyms are given in parentheses, +## but their use is discouraged): +## - default: Use the font's native hinter if possible, else FreeType's auto-hinter. +## ("either" is a synonym). +## - no_autohint: Use the font's native hinter if possible, else don't hint. +## ("native" is a synonym.) +## - force_autohint: Use FreeType's auto-hinter. ("auto" is a synonym.) +## - no_hinting: Disable hinting. ("none" is a synonym.) +#text.hinting: default + +#text.hinting_factor: None # This setting does nothing and is deprecated. +#text.kerning_factor: None # Specifies the scaling factor for kerning values. Values + # other than 0, 6, or None have no defined meaning. + # This setting is deprecated. +#text.antialiased: True # If True (default), the text will be antialiased. + # This only affects raster outputs. +#text.parse_math: True # Use mathtext if there is an even number of unescaped + # dollar signs. + + +## *************************************************************************** +## * LaTeX * +## *************************************************************************** +## For more information on LaTeX properties, see +## https://matplotlib.org/stable/users/explain/text/usetex.html +#text.usetex: False # use latex for all text handling. The following fonts + # are supported through the usual rc parameter settings: + # new century schoolbook, bookman, times, palatino, + # zapf chancery, charter, serif, sans-serif, helvetica, + # avant garde, courier, monospace, computer modern roman, + # computer modern sans serif, computer modern typewriter + +## The TeX engine/format to use. The following values are supported: +## - "latex": The classic TeX engine (the current default). All backends render +## TeX's output by parsing the DVI output into glyphs and boxes and emitting +## those one by one. +## - "latex+dvipng": The same as "latex", with the exception that Agg-based +## backends rely on dvipng to rasterize TeX's output. This value was the +## default up to Matplotlib 3.10. +#text.latex.engine: latex + +#text.latex.preamble: # IMPROPER USE OF THIS FEATURE WILL LEAD TO LATEX FAILURES + # AND IS THEREFORE UNSUPPORTED. PLEASE DO NOT ASK FOR HELP + # IF THIS FEATURE DOES NOT DO WHAT YOU EXPECT IT TO. + # text.latex.preamble is a single line of LaTeX code that + # will be passed on to the LaTeX system. It may contain + # any code that is valid for the LaTeX "preamble", i.e. + # between the "\documentclass" and "\begin{document}" + # statements. + # Note that it has to be put on a single line, which may + # become quite long. + # The following packages are always loaded with usetex, + # so beware of package collisions: + # color, fix-cm, geometry, graphicx, textcomp. + # PostScript (PSNFSS) font packages may also be + # loaded, depending on your font settings. + +## The following settings allow you to select the fonts in math mode. +#mathtext.fontset: dejavusans # Should be 'dejavusans' (default), + # 'dejavuserif', 'cm' (Computer Modern), 'stix', + # 'stixsans' or 'custom' +## "mathtext.fontset: custom" is defined by the mathtext.bf, .cal, .it, ... +## settings which map a TeX font name to a fontconfig font pattern. (These +## settings are not used for other font sets.) +#mathtext.bf: sans:bold +#mathtext.bfit: sans:italic:bold +#mathtext.cal: cursive +#mathtext.it: sans:italic +#mathtext.rm: sans +#mathtext.sf: sans +#mathtext.tt: monospace +#mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix' + # 'stixsans'] when a symbol cannot be found in one of the + # custom math fonts. Select 'None' to not perform fallback + # and replace the missing character by a dummy symbol. +#mathtext.default: normal # The default font to use for math. + # Can be any of the LaTeX font names (normal, it, bf, + # etc.), including the special name "regular" for the + # same font used in regular text. + + +## *************************************************************************** +## * AXES * +## *************************************************************************** +## Following are default face and edge colors, default tick sizes, +## default font sizes for tick labels, and so on. See +## https://matplotlib.org/stable/api/axes_api.html#module-matplotlib.axes +#axes.facecolor: white # axes background color +#axes.edgecolor: black # axes edge color +#axes.linewidth: 0.8 # edge line width +#axes.grid: False # display grid or not +#axes.grid.axis: both # which axis the grid should apply to +#axes.grid.which: major # grid lines at {major, minor, both} ticks +#axes.titlelocation: center # alignment of the title: {left, right, center} +#axes.titlesize: large # font size of the axes title +#axes.titleweight: normal # font weight of title +#axes.titlecolor: auto # color of the axes title, auto falls back to + # text.color as default value +#axes.titley: None # position title (axes relative units). None implies auto +#axes.titlepad: 6.0 # pad between axes and title in points +#axes.labelsize: medium # font size of the x and y labels +#axes.labelpad: 4.0 # space between label and axis +#axes.labelweight: normal # weight of the x and y labels +#axes.labelcolor: black +#axes.axisbelow: line # draw axis gridlines and ticks: + # - below patches (True) + # - above patches but below lines ('line') + # - above all (False) + +#axes.formatter.limits: -5, 6 # use scientific notation if log10 + # of the axis range is smaller than the + # first or larger than the second +#axes.formatter.use_locale: False # When True, format tick labels + # according to the user's locale. + # For example, use ',' as a decimal + # separator in the fr_FR locale. +#axes.formatter.use_mathtext: False # When True, use mathtext for scientific + # notation. +#axes.formatter.min_exponent: 0 # minimum exponent to format in scientific notation +#axes.formatter.useoffset: True # If True, the tick label formatter + # will default to labeling ticks relative + # to an offset when the data range is + # small compared to the minimum absolute + # value of the data. +#axes.formatter.offset_threshold: 4 # When useoffset is True, the offset + # will be used when it can remove + # at least this number of significant + # digits from tick labels. + +#axes.spines.left: True # display axis spines +#axes.spines.bottom: True +#axes.spines.top: True +#axes.spines.right: True + +#axes.unicode_minus: True # use Unicode for the minus symbol rather than hyphen. See + # https://en.wikipedia.org/wiki/Plus_and_minus_signs#Character_codes +#axes.prop_cycle: cycler(color='tab10') + # color cycle for plot lines as either a named color sequence or a list + # of string color specs: single letter, long name, or web-style hex + # As opposed to all other parameters in this file, the color + # values must be enclosed in quotes for this parameter, + # e.g. '1f77b4', instead of 1f77b4. + # See also https://matplotlib.org/stable/users/explain/artists/color_cycle.html + # for more details on prop_cycle usage. +#axes.xmargin: .05 # x margin. See `axes.Axes.margins` +#axes.ymargin: .05 # y margin. See `axes.Axes.margins` +#axes.zmargin: .05 # z margin. See `axes.Axes.margins` +#axes.autolimit_mode: data # If "data", use axes.xmargin and axes.ymargin as is. + # If "round_numbers", after application of margins, axis + # limits are further expanded to the nearest "round" number. +#polaraxes.grid: True # display grid on polar axes +#axes3d.grid: True # display grid on 3D axes +#axes3d.automargin: False # automatically add margin when manually setting 3D axis limits + +#axes3d.xaxis.panecolor: (0.95, 0.95, 0.95, 0.5) # background pane on 3D axes +#axes3d.yaxis.panecolor: (0.90, 0.90, 0.90, 0.5) # background pane on 3D axes +#axes3d.zaxis.panecolor: (0.925, 0.925, 0.925, 0.5) # background pane on 3D axes + +#axes3d.depthshade: True # depth shade for 3D scatter plots +#axes3d.depthshade_minalpha: 0.3 # minimum alpha value for depth shading + +#axes3d.mouserotationstyle: arcball # {azel, trackball, sphere, arcball} + # See also https://matplotlib.org/stable/api/toolkits/mplot3d/view_angles.html#rotation-with-mouse +#axes3d.trackballsize: 0.667 # trackball diameter, in units of the Axes bbox +#axes3d.trackballborder: 0.2 # trackball border width, in units of the Axes bbox (only for 'sphere' and 'arcball' style) +#axes3d.snap_rotation: 5.0 # Snap angle (degrees) for 3D rotation when holding Control. +## *************************************************************************** +## * AXIS * +## *************************************************************************** +#xaxis.labellocation: center # alignment of the xaxis label: {left, right, center} +#yaxis.labellocation: center # alignment of the yaxis label: {bottom, top, center} + + +## *************************************************************************** +## * DATES * +## *************************************************************************** +## These control the default format strings used in AutoDateFormatter. +## Any valid format datetime format string can be used (see the python +## `datetime` for details). For example, by using: +## - '%x' will use the locale date representation +## - '%X' will use the locale time representation +## - '%c' will use the full locale datetime representation +## These values map to the scales: +## {'year': 365, 'month': 30, 'day': 1, 'hour': 1/24, 'minute': 1 / (24 * 60)} + +#date.autoformatter.year: %Y +#date.autoformatter.month: %Y-%m +#date.autoformatter.day: %Y-%m-%d +#date.autoformatter.hour: %m-%d %H +#date.autoformatter.minute: %d %H:%M +#date.autoformatter.second: %H:%M:%S +#date.autoformatter.microsecond: %M:%S.%f +## The reference date for Matplotlib's internal date representation +## See https://matplotlib.org/stable/gallery/ticks/date_precision_and_epochs.html +#date.epoch: 1970-01-01T00:00:00 +## 'auto', 'concise': +#date.converter: auto +## For auto converter whether to use interval_multiples: +#date.interval_multiples: True + +## *************************************************************************** +## * TICKS * +## *************************************************************************** +## See https://matplotlib.org/stable/api/axis_api.html#matplotlib.axis.Tick +#xtick.top: False # draw ticks on the top side +#xtick.bottom: True # draw ticks on the bottom side +#xtick.labeltop: False # draw label on the top +#xtick.labelbottom: True # draw label on the bottom +#xtick.major.size: 3.5 # major tick size in points +#xtick.minor.size: 2 # minor tick size in points +#xtick.major.width: 0.8 # major tick width in points +#xtick.minor.width: 0.6 # minor tick width in points +#xtick.major.pad: 3.5 # distance to major tick label in points +#xtick.minor.pad: 3.4 # distance to the minor tick label in points +#xtick.color: black # color of the ticks +#xtick.labelcolor: inherit # color of the tick labels or inherit from xtick.color +#xtick.labelsize: medium # font size of the tick labels +#xtick.direction: out # direction: {in, out, inout} +#xtick.minor.visible: False # visibility of minor ticks on x-axis +#xtick.major.top: True # draw x axis top major ticks +#xtick.major.bottom: True # draw x axis bottom major ticks +#xtick.minor.top: True # draw x axis top minor ticks +#xtick.minor.bottom: True # draw x axis bottom minor ticks +#xtick.minor.ndivs: auto # number of minor ticks between the major ticks on x-axis +#xtick.alignment: center # alignment of xticks + +#ytick.left: True # draw ticks on the left side +#ytick.right: False # draw ticks on the right side +#ytick.labelleft: True # draw tick labels on the left side +#ytick.labelright: False # draw tick labels on the right side +#ytick.major.size: 3.5 # major tick size in points +#ytick.minor.size: 2 # minor tick size in points +#ytick.major.width: 0.8 # major tick width in points +#ytick.minor.width: 0.6 # minor tick width in points +#ytick.major.pad: 3.5 # distance to major tick label in points +#ytick.minor.pad: 3.4 # distance to the minor tick label in points +#ytick.color: black # color of the ticks +#ytick.labelcolor: inherit # color of the tick labels or inherit from ytick.color +#ytick.labelsize: medium # font size of the tick labels +#ytick.direction: out # direction: {in, out, inout} +#ytick.minor.visible: False # visibility of minor ticks on y-axis +#ytick.major.left: True # draw y axis left major ticks +#ytick.major.right: True # draw y axis right major ticks +#ytick.minor.left: True # draw y axis left minor ticks +#ytick.minor.right: True # draw y axis right minor ticks +#ytick.minor.ndivs: auto # number of minor ticks between the major ticks on y-axis +#ytick.alignment: center_baseline # alignment of yticks + + +## *************************************************************************** +## * GRIDS * +## *************************************************************************** +#grid.color: "#b0b0b0" # grid color +#grid.linestyle: - # solid +#grid.linewidth: 0.8 # in points +#grid.alpha: 1.0 # transparency, between 0.0 and 1.0 + +#grid.major.color: None # If None defaults to grid.color +#grid.major.linestyle: None # If None defaults to grid.linestyle +#grid.major.linewidth: None # If None defaults to grid.linewidth +#grid.major.alpha: None # If None defaults to grid.alpha + +#grid.minor.color: None # If None defaults to grid.color +#grid.minor.linestyle: None # If None defaults to grid.linestyle +#grid.minor.linewidth: None # If None defaults to grid.linewidth +#grid.minor.alpha: None # If None defaults to grid.alpha + + +## *************************************************************************** +## * LEGEND * +## *************************************************************************** +#legend.loc: best +#legend.frameon: True # if True, draw the legend on a background patch +#legend.framealpha: 0.8 # legend patch transparency +#legend.facecolor: inherit # inherit from axes.facecolor; or color spec +#legend.edgecolor: 0.8 # background patch boundary color +#legend.linewidth: None # line width of the legend frame, None means inherit from patch.linewidth +#legend.fancybox: True # if True, use a rounded box for the + # legend background, else a rectangle +#legend.shadow: False # if True, give background a shadow effect +#legend.numpoints: 1 # the number of marker points in the legend line +#legend.scatterpoints: 1 # number of scatter points +#legend.markerscale: 1.0 # the relative size of legend markers vs. original +#legend.fontsize: medium +#legend.labelcolor: None +#legend.title_fontsize: None # None sets to the same as the default axes. + +## Dimensions as fraction of font size: +#legend.borderpad: 0.4 # border whitespace +#legend.labelspacing: 0.5 # the vertical space between the legend entries +#legend.handlelength: 2.0 # the length of the legend lines +#legend.handleheight: 0.7 # the height of the legend handle +#legend.handletextpad: 0.8 # the space between the legend line and legend text +#legend.borderaxespad: 0.5 # the border between the axes and legend edge +#legend.columnspacing: 2.0 # column separation + + +## *************************************************************************** +## * FIGURE * +## *************************************************************************** +## See https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure +#figure.titlesize: large # size of the figure title (``Figure.suptitle()``) +#figure.titleweight: normal # weight of the figure title +#figure.labelsize: large # size of the figure label (``Figure.sup[x|y]label()``) +#figure.labelweight: normal # weight of the figure label +#figure.figsize: 6.4, 4.8 # figure size in inches +#figure.dpi: 100 # figure dots per inch +#figure.facecolor: white # figure face color +#figure.edgecolor: white # figure edge color +#figure.frameon: True # enable figure frame +#figure.max_open_warning: 20 # The maximum number of figures to open through + # the pyplot interface before emitting a warning. + # If less than one this feature is disabled. +#figure.raise_window : True # Raise the GUI window to front when show() is called. + # If set to False, we currently do not take any further + # actions and whether the window appears on the front + # may depend on the GUI framework and window manager. + +## The figure subplot parameters. All dimensions are a fraction of the figure width and height. +#figure.subplot.left: 0.125 # the left side of the subplots of the figure +#figure.subplot.right: 0.9 # the right side of the subplots of the figure +#figure.subplot.bottom: 0.11 # the bottom of the subplots of the figure +#figure.subplot.top: 0.88 # the top of the subplots of the figure +#figure.subplot.wspace: 0.2 # the amount of width reserved for space between subplots, + # expressed as a fraction of the average axis width +#figure.subplot.hspace: 0.2 # the amount of height reserved for space between subplots, + # expressed as a fraction of the average axis height + +## Figure layout +#figure.autolayout: False # When True, automatically adjust subplot + # parameters to make the plot fit the figure + # using `tight_layout` +#figure.constrained_layout.use: False # When True, automatically make plot + # elements fit on the figure. (Not + # compatible with `autolayout`, above). +## Padding (in inches) around axes; defaults to 3/72 inches, i.e. 3 points. +#figure.constrained_layout.h_pad: 0.04167 +#figure.constrained_layout.w_pad: 0.04167 +## Spacing between subplots, relative to the subplot sizes. Much smaller than for +## tight_layout (figure.subplot.hspace, figure.subplot.wspace) as constrained_layout +## already takes surrounding texts (titles, labels, # ticklabels) into account. +#figure.constrained_layout.hspace: 0.02 +#figure.constrained_layout.wspace: 0.02 + + +## *************************************************************************** +## * IMAGES * +## *************************************************************************** +#image.aspect: equal # {equal, auto} or a number +#image.interpolation: auto # see help(imshow) for options +#image.interpolation_stage: auto # see help(imshow) for options +#image.cmap: viridis # A colormap name (plasma, magma, etc.) +#image.lut: 256 # the size of the colormap lookup table +#image.origin: upper # {lower, upper} +#image.resample: True +#image.composite_image: True # When True, all the images on a set of axes are + # combined into a single composite image before + # saving a figure as a vector graphics file, + # such as a PDF. + + +## *************************************************************************** +## * CONTOUR PLOTS * +## *************************************************************************** +#contour.negative_linestyle: dashed # string or on-off ink sequence +#contour.corner_mask: True # {True, False} +#contour.linewidth: None # {float, None} Size of the contour line + # widths. If set to None, it falls back to + # `line.linewidth`. +#contour.algorithm: mpl2014 # {mpl2005, mpl2014, serial, threaded} + + +## *************************************************************************** +## * ERRORBAR PLOTS * +## *************************************************************************** +#errorbar.capsize: 0 # length of end cap on error bars in pixels +#errorbar.capthick: None # thickness of end cap on error bars in points +#errorbar.elinewidth: None # line width of error bar lines in points + + +## *************************************************************************** +## * HISTOGRAM PLOTS * +## *************************************************************************** +#hist.bins: 10 # The default number of histogram bins or 'auto'. + + +## *************************************************************************** +## * SCATTER PLOTS * +## *************************************************************************** +#scatter.marker: o # The default marker type for scatter plots. +#scatter.edgecolors: face # The default edge colors for scatter plots. + + +## *************************************************************************** +## * AGG RENDERING * +## *************************************************************************** +## Warning: experimental, 2008/10/10 +#agg.path.chunksize: 0 # 0 to disable; values in the range + # 10000 to 100000 can improve speed slightly + # and prevent an Agg rendering failure + # when plotting very large data sets, + # especially if they are very gappy. + # It may cause minor artifacts, though. + # A value of 20000 is probably a good + # starting point. + + +## *************************************************************************** +## * PATHS * +## *************************************************************************** +#path.simplify: True # When True, simplify paths by removing "invisible" + # points to reduce file size and increase rendering + # speed +#path.simplify_threshold: 0.111111111111 # The threshold of similarity below + # which vertices will be removed in + # the simplification process. +#path.snap: True # When True, rectilinear axis-aligned paths will be snapped + # to the nearest pixel when certain criteria are met. + # When False, paths will never be snapped. +#path.sketch: None # May be None, or a tuple of the form: + # path.sketch: (scale, length, randomness) + # - *scale* is the amplitude of the wiggle + # perpendicular to the line (in pixels). + # - *length* is the length of the wiggle along the + # line (in pixels). + # - *randomness* is the factor by which the length is + # randomly scaled. +#path.effects: + + +## *************************************************************************** +## * SAVING FIGURES * +## *************************************************************************** +## The default savefig parameters can be different from the display parameters +## e.g., you may want a higher resolution, or to make the figure +## background white +#savefig.dpi: figure # figure dots per inch or 'figure' +#savefig.facecolor: auto # figure face color when saving +#savefig.edgecolor: auto # figure edge color when saving +#savefig.format: png # {png, ps, pdf, svg} +#savefig.bbox: standard # {tight, standard} + # 'tight' is incompatible with generating frames + # for animation +#savefig.pad_inches: 0.1 # padding to be used, when bbox is set to 'tight' +#savefig.directory: ~ # default directory in savefig dialog, gets updated after + # interactive saves, unless set to the empty string (i.e. + # the current directory); use '.' to start at the current + # directory but update after interactive saves +#savefig.transparent: False # whether figures are saved with a transparent + # background by default +#savefig.orientation: portrait # orientation of saved figure, for PostScript output only + +### macosx backend params +#macosx.window_mode : system # How to open new figures (system, tab, window) + # system uses the MacOS system preferences + +### tk backend params +#tk.window_focus: False # Maintain shell focus for TkAgg + +### ps backend params +#ps.papersize: letter # {figure, letter, legal, ledger, A0-A10, B0-B10} +#ps.useafm: False # use AFM fonts, results in small files +#ps.usedistiller: False # {ghostscript, xpdf, None} + # Experimental: may produce smaller files. + # xpdf intended for production of publication quality files, + # but requires ghostscript, xpdf and ps2eps +#ps.distiller.res: 6000 # dpi +#ps.fonttype: 3 # Output Type 3 (Type3) or Type 42 (TrueType) + +### PDF backend params +#pdf.compression: 6 # integer from 0 to 9 + # 0 disables compression (good for debugging) +#pdf.fonttype: 3 # Output Type 3 (Type3) or Type 42 (TrueType) +#pdf.use14corefonts: False +#pdf.inheritcolor: False + +### SVG backend params +#svg.image_inline: True # Write raster image data directly into the SVG file +#svg.fonttype: path # How to handle SVG fonts: + # path: Embed characters as paths -- supported + # by most SVG renderers + # none: Assume fonts are installed on the + # machine where the SVG will be viewed. +#svg.hashsalt: None # If not None, use this string as hash salt instead of uuid4 +#svg.id: None # If not None, use this string as the value for the `id` + # attribute in the top tag + +### pgf parameter +## See https://matplotlib.org/stable/tutorials/text/pgf.html for more information. +#pgf.rcfonts: True +#pgf.preamble: # See text.latex.preamble for documentation +#pgf.texsystem: xelatex + +### docstring params +#docstring.hardcopy: False # set this when you want to generate hardcopy docstring + + +## *************************************************************************** +## * INTERACTIVE KEYMAPS * +## *************************************************************************** +## Event keys to interact with figures/plots via keyboard. +## See https://matplotlib.org/stable/users/explain/interactive.html for more +## details on interactive navigation. Customize these settings according to +## your needs. Leave the field(s) empty if you don't need a key-map. (i.e., +## fullscreen : '') +#keymap.fullscreen: f, ctrl+f # toggling +#keymap.home: h, r, home # home or reset mnemonic +#keymap.back: left, c, backspace, MouseButton.BACK # forward / backward keys +#keymap.forward: right, v, MouseButton.FORWARD # for quick navigation +#keymap.pan: p # pan mnemonic +#keymap.zoom: o # zoom mnemonic +#keymap.save: s, ctrl+s # saving current figure +#keymap.help: f1 # display help about active tools +#keymap.quit: ctrl+w, cmd+w, q # close the current figure +#keymap.quit_all: # close all figures +#keymap.grid: g # switching on/off major grids in current axes +#keymap.grid_minor: G # switching on/off minor grids in current axes +#keymap.yscale: l # toggle scaling of y-axes ('log'/'linear') +#keymap.xscale: k, L # toggle scaling of x-axes ('log'/'linear') +#keymap.copy: ctrl+c, cmd+c # copy figure to clipboard + + +## *************************************************************************** +## * ANIMATION * +## *************************************************************************** +#animation.html: none # How to display the animation as HTML in + # the IPython notebook: + # - 'html5' uses HTML5 video tag + # - 'jshtml' creates a JavaScript animation +#animation.writer: ffmpeg # MovieWriter 'backend' to use +#animation.codec: h264 # Codec to use for writing movie +#animation.bitrate: -1 # Controls size/quality trade-off for movie. + # -1 implies let utility auto-determine +#animation.frame_format: png # Controls frame format used by temp files + +## Path to ffmpeg binary. Unqualified paths are resolved by subprocess.Popen. +#animation.ffmpeg_path: ffmpeg +## Additional arguments to pass to ffmpeg. +#animation.ffmpeg_args: + +## Path to ImageMagick's convert binary. Unqualified paths are resolved by +## subprocess.Popen, except that on Windows, we look up an install of +## ImageMagick in the registry (as convert is also the name of a system tool). +#animation.convert_path: convert +## Additional arguments to pass to convert. +#animation.convert_args: -layers, OptimizePlus +# +#animation.embed_limit: 20.0 # Limit, in MB, of size of base64 encoded + # animation in HTML (i.e. IPython notebook) \ No newline at end of file diff --git a/defs/computing.py b/defs/computing.py index 6016f69..6827a6c 100644 --- a/defs/computing.py +++ b/defs/computing.py @@ -4,11 +4,71 @@ import numpy as np import pandas as pd import math -import matplotlib.pyplot as plt +import warnings +import codecs ### ----------------------------------------------------------------------------------------------------------------------------------- ### ### OFR ANALYSIS +class Distribution(): + + def __init__(self, variable_array, function_array, form = 'log10'): + + self.var = variable_array + self.fct = function_array + + self.__form = form + + def transform(self, to = 'linear'): + + if self.__form == to: + warnings.warn("Already in desired format. Transformation has no effect.") + return + + # TODO: check the transformations! + + match to: + case 'linear': + if self.__form == 'ln': + self.var = np.exp(self.var) + self.fct = np.divide(self.fct, self.var) + elif self.__form == 'log10': + self.var = np.power(10, self.var) + self.fct = np.divide(self.fct, self.var * np.log(10)) + case 'ln': + if self.__form == 'linear': + self.var = np.log(self.var) + self.fct = np.multiply(self.var, self.fct) + elif self.__form == 'log10': + self.var = np.log(np.power(10, self.var)) + self.fct = np.divide(self.fct, np.log(10)) + case 'log10': + if self.__form == 'linear': + self.var = np.log10(self.var) + self.fct = np.multiply(self.var, self.fct * np.log(10)) + elif self.__form == 'ln': + self.var = np.log10(np.exp(self.var)) + self.fct = np.multiply(self.fct, np.log(10)) + + def integrate(self) -> np.float64: + return np.trapezoid(y = self.fct, x = self.var) + + def median(): + # TODO: implement that method + pass + + def mode(): + # TODO: implement that method + pass + + def mean(): + # TODO: implement that method + pass + + def variance(): + # TODO: implement that method + pass + class OFRSample: """Object to represent a single sample from the OFR @@ -40,48 +100,7 @@ class OFRSample: The density (kg/m3) of the SOA produced in the OFR """ - def __init__(self, source_file, sample_number, data_separator): - - # Sample information - self.source_file = source_file # where the data is stored, i.e. "C:/Users/tschan_d/..." - self.sample_number = sample_number # sample number, i.e. 33 - self.__data_separator = data_separator - - self.scan_up_time = None # Time to scan up the voltage range in DMA, in (s) - self.scan_down_time = None # Time to scan down the voltage range in DMA, in(s) - - self.sample_time = None - - self.lower_diameter_bound = None # Lower Diameter bound of CPC, in (nm) - self.upper_diameter_bound = None # Upper Diameter bound of CPC, in (nm) - self.aerosol_flow = None # Aerosol flow, in (m3/s) - self.SOA_density = None # Expected density of SOA, in (kg/m3) - - # Sample Distributions - self.diameters = None # Bin Midpoint Diameter, in (m) - self.count_density = None # Count Density dN/dlnD, in (#/m3) - self.surface_density = None # Surface Density dS/dlnD, in (m2/(m3*m)) - self.volume_density = None # Volume Density dV/dlnD, in (m3/(m3*m)) - self.mass_density = None # Mass Density dm/dlnD, in (kg/(m3*m)) - - # Distributed integrated along dlnD - self.sample_count_density = None # Total Count Density (#/(m3)) - self.sample_surface_density = None # Total Surface Density (m2/(m3)) - self.sample_volume_density = None # Total Volume Density (m3/(m3)) - self.sample_mass_density = None # Total Mass Density (kg/(m3)) - - # Distributions integrated over sample - self.sample_count = None # Total Count (#/(m3)) - self.sample_surface = None # Total Surface (m2/(m3)) - self.sample_volume = None # Total Volume (m3/(m3)) - self.sample_mass = None # Total Mass (kg/(m3)) - - self.__get_data() - self.__get_distributions() - self.__integrate_over_distributions() - self.__integrate_over_sample() - - def __get_data(self): + def __get_data(self) -> np.float64: footer_flag = False footer_start_index = 0 @@ -91,7 +110,7 @@ class OFRSample: midpoints = [] counts = [] - with open(self.source_file, 'r') as file: + with open(self.source_file, 'r', errors = 'ignore') as file: for i, line in enumerate(file.readlines()): if i == 20: data_flag = True @@ -111,7 +130,7 @@ class OFRSample: self.scan_down_time = float(line.split(self.__data_separator)[1]) continue elif i == footer_start_index + 6: - self.aerosol_flow = float(line.split(self.__data_separator)[1]) / 60000 + self.aerosol_flow = float(line.split(self.__data_separator)[1]) continue elif i == footer_start_index + 11: self.lower_diameter_bound = float(line.split(self.__data_separator)[1]) @@ -120,7 +139,7 @@ class OFRSample: self.upper_diameter_bound = float(line.split(self.__data_separator)[1]) continue elif i == footer_start_index + 13: - self.SOA_density = float(line.split(self.__data_separator)[1]) * 1E3 + self.SOA_density = float(line.split(self.__data_separator)[1]) continue self.sample_time = self.scan_up_time + self.scan_down_time @@ -136,45 +155,54 @@ class OFRSample: else: continue - # Input data from file is in (nm). Therefore, multiply with 1E-9 to get (m) - self.diameters = np.array(midpoints).reshape([-1, 1]) * 1E-9 + # Input data from file is in (nm) + return [np.array(midpoints), np.array(counts)] - # Input data from file is in (#/cm3). Therefore, multiply with 1E6 to get (#/m3) - self.count_density = np.array(counts).reshape([-1, 1]) * 1E6 - - def __get_distributions(self): + def __init__(self, source_file, sample_number, data_separator = ','): - self.surface_density = (math.pi * self.diameters ** 2) * self.count_density - self.volume_density = (math.pi * self.diameters ** 3) * self.count_density - self.mass_density = self.SOA_density * self.volume_density + ## VALUES READ IN FROM DISK + #-------------------------- - def __integrate_over_distributions(self): + # Sample information + self.source_file = source_file # where the data is stored, i.e. "C:/Users/tschan_d/..." + self.sample_number = sample_number # sample number, i.e. 33 + self.__data_separator = data_separator - self.sample_count_density = self.__integrator(integrand=np.divide(self.count_density, self.diameters)) - self.sample_surface_density = self.__integrator(integrand=np.divide(self.surface_density, self.diameters)) - self.sample_volume_density = self.__integrator(integrand=np.divide(self.volume_density, self.diameters)) - self.sample_mass_density = self.__integrator(integrand=np.divide(self.mass_density, self.diameters)) + self.scan_up_time = None # Time to scan up the voltage range in DMA, in (s) + self.scan_down_time = None # Time to scan down the voltage range in DMA, in(s) + self.sample_time = None # Total time to scan voltage up and back down in DMA, in (s) - def __integrator(self, integrand: np.float64) -> np.float64: - - return np.trapezoid(y = integrand.flatten(), x = self.diameters.flatten()) - - def __integrate_over_sample(self): - - self.sample_count = self.sample_count_density * self.sample_time * self.aerosol_flow - self.sample_surface = self.sample_surface_density * self.sample_time * self.aerosol_flow - self.sample_volume = self.sample_volume_density * self.sample_time * self.aerosol_flow - self.sample_mass = self.sample_mass_density * self.sample_time * self.aerosol_flow + self.lower_diameter_bound = None # Lower Diameter bound of CPC, in (nm) + self.upper_diameter_bound = None # Upper Diameter bound of CPC, in (nm) + self.aerosol_flow = None # Aerosol flow, in (L/min) + self.SOA_density = None # Expected density of SOA, in (g/cm3) + # Distributions of the relevant quantities (all relative to nanometer) + data = self.__get_data() + self.Count = Distribution(variable_array = np.log10(data[0]), + function_array = data[1], + form='log10') + self.Length = Distribution(variable_array = np.log10(data[0]), + function_array = data[0] * data[1], + form = 'log10') + self.Surface = Distribution(variable_array = np.log(data[0]), + function_array = ((math.pi) * data[0] ** 2) * data[1], + form = 'log10') + self.Volume = Distribution(variable_array = np.log10(data[0]), + function_array = ((math.pi / 6) * data[0] ** 3) * data[1], + form = 'log10') + self.Mass = Distribution(variable_array = np.log10(data[0]), + function_array = (self.SOA_density * (math.pi / 6) * data[0] ** 3) * data[1], + form='log10') class OFRAnalyser: - def __init__(self, source_file, data_separator = ',') -> None: + def __init__(self, source_file, sample_number_list, data_separator = ',') -> None: self.source_file = source_file self.__data_separator = data_separator - with open(self.source_file, 'r') as file: + with open(self.source_file, 'r', errors = 'ignore') as file: for i, line in enumerate(file.readlines()): if i == 17: items = line.split(',') @@ -183,10 +211,10 @@ class OFRAnalyser: continue self.max_samples = max_sample_number - self.total_counts = None - self.total_surface = None - self.total_volume = None - self.total_mass = None + self.sample_number_list = sample_number_list + + self.data = None + def __sample_number_list_check(self, sample_number_list) -> None: @@ -195,27 +223,39 @@ class OFRAnalyser: if last_sample > self.max_samples: raise IndexError("The last sample(s) are out of range of the number of recorded samples") - def AggregateSamples(self, samples = [1]) -> None: + def Analyse(self) -> None: - self.__sample_number_list_check(samples) + self.__sample_number_list_check(self.sample_number_list) - counts = [] + numbers = [] + lengths = [] surfaces = [] volumes = [] + densities = [] masses = [] + times = [] + + for sample_number in self.sample_number_list: + sample = OFRSample(source_file=self.source_file, sample_number = sample_number, data_separator = self.__data_separator) + + numbers.append(sample.Count.integrate()) + lengths.append(sample.Length.integrate() / 1E6) + surfaces.append(sample.Surface.integrate() / 1E12) + volumes.append(sample.Volume.integrate() / 1E9) + densities.append(sample.SOA_density) + masses.append(sample.Mass.integrate() / 1E12) + times.append(sample_number * sample.sample_time) + + self.data = pd.DataFrame({'Sample': self.sample_number_list, + 'Number (#/cm^3)': numbers, + 'Length (mm/cm^3)': lengths, + 'Surface (mm^2/cm^3)': surfaces, + 'Volume (μm^3/cm^3)': volumes, + 'Density (pg/μm^3)': densities, + 'Mass (mg/cm^3)': masses, + 'Time (s)': times}) - for samplenumber in samples: - sample = OFRSample(source_file=self.source_file, sample_number = samplenumber, data_separator = self.__data_separator) - counts.append(sample.sample_count) - surfaces.append(sample.sample_surface) - volumes.append(sample.sample_volume) - masses.append(sample.sample_mass) - - self.total_counts = sum(counts) - self.total_surface = sum(surfaces) - self.total_volume = sum(volumes) - self.total_mass = sum(masses) ### ----------------------------------------------------------------------------------------------------------------------------------- ### ### \ No newline at end of file diff --git a/main.html b/main.html new file mode 100644 index 0000000..e6252ec --- /dev/null +++ b/main.html @@ -0,0 +1,61 @@ + + + + + Bokeh Plot + + + + + +
+ + + + + \ No newline at end of file diff --git a/main.py b/main.py index e83e7ab..0f97bfd 100644 --- a/main.py +++ b/main.py @@ -1,16 +1,22 @@ +# Imports #%% -from pathlib import Path -from defs.computing import OFRAnalyser +from defs.computing import OFRSample, OFRAnalyser import numpy as np +from bokeh.plotting import figure, show +from pathlib import Path -#%% -analyser = OFRAnalyser(source_file=Path(r"Z:\People\David_Tschan\data\OFR_SMPS\2026\processed\06_June\20260612\20260612_SET02_EXP01_full.txt")) +# Path to the source file +source_file = Path(r"C:\Users\tschan_d\Documents\data_local\20260612_SET02_EXP01_full.txt") -#samplelist = np.linspace(start=1, stop=analyser.max_samples, num=analyser.max_samples, dtype=int).tolist() +# Plotting one of the spectra to show properties + +# first load and get the data of sample 57 (arbitrary) +sample = OFRSample(source_file = source_file, sample_number = 150) + +# Now plot the spectrum +p = figure(width = 600, height = 400, x_axis_type='log') +p.line(x = sample.Count.var, y = sample.Count.fct) +show(p) -#%% -analyser.AggregateSamples(samples=[33]) -#%% -print(analyser.total_mass) # %% diff --git a/run/202607023_OFR_Analysis_01.ipynb b/run/202607023_OFR_Analysis_01.ipynb new file mode 100644 index 0000000..cf2ba75 --- /dev/null +++ b/run/202607023_OFR_Analysis_01.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "36f6dc0f", + "metadata": {}, + "source": [ + "### OFR Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "8769766b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + "
\n", + " \n", + " Loading BokehJS ...\n", + "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "'use strict';\n(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n\n if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\nconst JS_MIME_TYPE = 'application/javascript';\n const HTML_MIME_TYPE = 'text/html';\n const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n const CLASS_NAME = 'output_bokeh rendered_html';\n\n /**\n * Render data to the DOM node\n */\n function render(props, node) {\n const script = document.createElement(\"script\");\n node.appendChild(script);\n }\n\n /**\n * Handle when an output is cleared or removed\n */\n function handleClearOutput(event, handle) {\n function drop(id) {\n const view = Bokeh.index.get_by_id(id)\n if (view != null) {\n view.model.document.clear()\n Bokeh.index.delete(view)\n }\n }\n\n const cell = handle.cell;\n\n const id = cell.output_area._bokeh_element_id;\n const server_id = cell.output_area._bokeh_server_id;\n\n // Clean up Bokeh references\n if (id != null) {\n drop(id)\n }\n\n if (server_id !== undefined) {\n // Clean up Bokeh references\n const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n cell.notebook.kernel.execute(cmd_clean, {\n iopub: {\n output: function(msg) {\n const id = msg.content.text.trim()\n drop(id)\n }\n }\n });\n // Destroy server and session\n const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n cell.notebook.kernel.execute(cmd_destroy);\n }\n }\n\n /**\n * Handle when a new output is added\n */\n function handleAddOutput(event, handle) {\n const output_area = handle.output_area;\n const output = handle.output;\n\n // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n return\n }\n\n const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n\n if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n // store reference to embed id on output_area\n output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n }\n if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n const bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n const script_attrs = bk_div.children[0].attributes;\n for (let i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n }\n\n function register_renderer(events, OutputArea) {\n\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n const toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[toinsert.length - 1]);\n element.append(toinsert);\n return toinsert\n }\n\n /* Handle when an output is cleared or removed */\n events.on('clear_output.CodeCell', handleClearOutput);\n events.on('delete.Cell', handleClearOutput);\n\n /* Handle when a new output is added */\n events.on('output_added.OutputArea', handleAddOutput);\n\n /**\n * Register the mime type and append_mime function with output_area\n */\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n /* Is output safe? */\n safe: true,\n /* Index of renderer in `output_area.display_order` */\n index: 0\n });\n }\n\n // register the mime type if in Jupyter Notebook environment and previously unregistered\n if (root.Jupyter !== undefined) {\n const events = require('base/js/events');\n const OutputArea = require('notebook/js/outputarea').OutputArea;\n\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n }\n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n const NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded(error = null) {\n const el = document.getElementById(\"ba7b56ac-409d-4c6f-803b-da270f9806de\");\n if (el != null) {\n const html = (() => {\n if (typeof root.Bokeh === \"undefined\") {\n if (error == null) {\n return \"BokehJS is loading ...\";\n } else {\n return \"BokehJS failed to load.\";\n }\n } else {\n const prefix = `BokehJS ${root.Bokeh.version}`;\n if (error == null) {\n return `${prefix} successfully loaded.`;\n } else {\n return `${prefix} encountered errors while loading and may not function as expected.`;\n }\n }\n })();\n el.innerHTML = html;\n\n if (error != null) {\n const wrapper = document.createElement(\"div\");\n wrapper.style.overflow = \"auto\";\n wrapper.style.height = \"5em\";\n wrapper.style.resize = \"vertical\";\n const content = document.createElement(\"div\");\n content.style.fontFamily = \"monospace\";\n content.style.whiteSpace = \"pre-wrap\";\n content.style.backgroundColor = \"rgb(255, 221, 221)\";\n content.textContent = error.stack ?? error.toString();\n wrapper.append(content);\n el.append(wrapper);\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(() => display_loaded(error), 100);\n }\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n\n function on_error(url) {\n console.error(\"failed to load \" + url);\n }\n\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n }\n\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error.bind(null, url);\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.9.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.9.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.9.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.9.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.9.1.min.js\"];\n const css_urls = [];\n\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {\n }\n ];\n\n function run_inline_js() {\n if (root.Bokeh !== undefined || force === true) {\n try {\n for (let i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }\n\n } catch (error) {display_loaded(error);throw error;\n }if (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n const cell = $(document.getElementById(\"ba7b56ac-409d-4c6f-803b-da270f9806de\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n }\n\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(css_urls, js_urls, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));", + "application/vnd.bokehjs_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Imports\n", + "\n", + "from defs.computing import OFRSample, OFRAnalyser\n", + "import numpy as np\n", + "from pathlib import Path\n", + "\n", + "from bokeh.plotting import figure, show\n", + "from bokeh.io import output_notebook\n", + "output_notebook()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "3922e80c", + "metadata": {}, + "outputs": [], + "source": [ + "# Path to the source file\n", + "source_file = Path(r\"Z:\\People\\David_Tschan\\data\\OFR_SMPS\\2026\\processed\\06_June\\20260612\\20260612_SET02_EXP01_full.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76a9b026", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "unexpected attribute 'show' to figure, possible attributes are above, align, aspect_ratio, aspect_scale, attribution, background_fill_alpha, background_fill_color, background_hatch_alpha, background_hatch_color, background_hatch_extra, background_hatch_pattern, background_hatch_scale, background_hatch_weight, below, border_fill_alpha, border_fill_color, border_hatch_alpha, border_hatch_color, border_hatch_extra, border_hatch_pattern, border_hatch_scale, border_hatch_weight, border_line_alpha, border_line_cap, border_line_color, border_line_dash, border_line_dash_offset, border_line_join, border_line_width, center, context_menu, css_classes, css_variables, disabled, elements, extra_x_ranges, extra_x_scales, extra_y_ranges, extra_y_scales, flow_mode, frame_align, frame_height, frame_width, height, height_policy, hidpi, hold_render, html_attributes, html_id, inner_height, inner_width, js_event_callbacks, js_property_callbacks, left, lod_factor, lod_interval, lod_threshold, lod_timeout, margin, match_aspect, max_height, max_width, min_border, min_border_bottom, min_border_left, min_border_right, min_border_top, min_height, min_width, name, outer_height, outer_width, outline_line_alpha, outline_line_cap, outline_line_color, outline_line_dash, outline_line_dash_offset, outline_line_join, outline_line_width, output_backend, renderers, reset_policy, resizable, right, sizing_mode, styles, stylesheets, subscribed_events, syncable, tags, title, title_location, toolbar, toolbar_inner, toolbar_location, toolbar_sticky, visible, width, width_policy, window_axis, x_range, x_scale, y_range or y_scale", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAttributeError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[47]\u001b[39m\u001b[32m, line 9\u001b[39m\n\u001b[32m 5\u001b[39m \n\u001b[32m 6\u001b[39m p = figure(width=\u001b[32m600\u001b[39m, height=\u001b[32m400\u001b[39m, x_axis_type=\u001b[33m'log'\u001b[39m)\n\u001b[32m 7\u001b[39m p.line(np.power(\u001b[32m10\u001b[39m,sample.Count.var), sample.Count.fct)\n\u001b[32m 8\u001b[39m \n\u001b[32m----> \u001b[39m\u001b[32m9\u001b[39m p.show()\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\tschan_d\\AppData\\Local\\miniforge3\\envs\\MA\\Lib\\site-packages\\bokeh\\core\\has_props.py:373\u001b[39m, in \u001b[36mHasProps.__getattr__\u001b[39m\u001b[34m(self, name)\u001b[39m\n\u001b[32m 370\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(descriptor, \u001b[38;5;28mproperty\u001b[39m): \u001b[38;5;66;03m# Python property\u001b[39;00m\n\u001b[32m 371\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28msuper\u001b[39m().\u001b[34m__getattribute__\u001b[39m(name)\n\u001b[32m--> \u001b[39m\u001b[32m373\u001b[39m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_raise_attribute_error_with_matches\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43mname\u001b[39;49m\u001b[30;43m,\u001b[39;49m\u001b[30;43m \u001b[39;49m\u001b[30;43mproperties\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\tschan_d\\AppData\\Local\\miniforge3\\envs\\MA\\Lib\\site-packages\\bokeh\\core\\has_props.py:386\u001b[39m, in \u001b[36mHasProps._raise_attribute_error_with_matches\u001b[39m\u001b[34m(self, name, properties)\u001b[39m\n\u001b[32m 382\u001b[39m matches, text = \u001b[38;5;28msorted\u001b[39m(properties), \u001b[33m\"\u001b[39m\u001b[33mpossible\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 384\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01m.\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mutil\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mstrings\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m nice_join\n\u001b[32m--> \u001b[39m\u001b[32m386\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mAttributeError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33munexpected attribute \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m!r}\u001b[39;00m\u001b[33m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m.\u001b[34m__class__\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m, \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m attributes are \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mnice_join(matches)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mAttributeError\u001b[39m: unexpected attribute 'show' to figure, possible attributes are above, align, aspect_ratio, aspect_scale, attribution, background_fill_alpha, background_fill_color, background_hatch_alpha, background_hatch_color, background_hatch_extra, background_hatch_pattern, background_hatch_scale, background_hatch_weight, below, border_fill_alpha, border_fill_color, border_hatch_alpha, border_hatch_color, border_hatch_extra, border_hatch_pattern, border_hatch_scale, border_hatch_weight, border_line_alpha, border_line_cap, border_line_color, border_line_dash, border_line_dash_offset, border_line_join, border_line_width, center, context_menu, css_classes, css_variables, disabled, elements, extra_x_ranges, extra_x_scales, extra_y_ranges, extra_y_scales, flow_mode, frame_align, frame_height, frame_width, height, height_policy, hidpi, hold_render, html_attributes, html_id, inner_height, inner_width, js_event_callbacks, js_property_callbacks, left, lod_factor, lod_interval, lod_threshold, lod_timeout, margin, match_aspect, max_height, max_width, min_border, min_border_bottom, min_border_left, min_border_right, min_border_top, min_height, min_width, name, outer_height, outer_width, outline_line_alpha, outline_line_cap, outline_line_color, outline_line_dash, outline_line_dash_offset, outline_line_join, outline_line_width, output_backend, renderers, reset_policy, resizable, right, sizing_mode, styles, stylesheets, subscribed_events, syncable, tags, title, title_location, toolbar, toolbar_inner, toolbar_location, toolbar_sticky, visible, width, width_policy, window_axis, x_range, x_scale, y_range or y_scale" + ] + } + ], + "source": [ + "# Plotting one of the spectra to show properties\n", + "\n", + "# first load and get the data of sample 57 (arbitrary)\n", + "sample = OFRSample(source_file = source_file, sample_number = 33)\n", + "\n", + "p = figure(width=600, height=400, x_axis_type='log')\n", + "p.line(sample.Count.var, sample.Count.fct)\n", + "\n", + "p.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2363080b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "MA", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}