Miscellaneous¶
Good advice on miscellaneous topics:
Artifacts (1.6)¶
A useful guide: Artifacts for Dummies
Dates (1.6)¶
Working with time durations seems to require converting the durations to millisecond integers first:
d1 = DateTime(2021,9,10,9); d2 = d1 + Minute(3) + Second(5);
dSeconds = Dates.value(d2-d1) / 1000;
Going back to time units requires rounding because Minute(dSeconds)
throws an InexactError
.
dMinutes = Minute(round(dSeconds / 60));
There is no formatted display of durations, only of dates:
Dates.format(d1, "HH:MM");
Enum (1.6)¶
@enum Fruit apple=1 orange=2 kiwi=3
The type
is Fruit
(concrete). So dispatch on the instances does not work.
EnumX.jl
packages enums in a module. Avoids namespace conflicts.
Alternatives:
- Define an abstract type with concrete subtypes
Apple <: AbstractFruit
. - Make parametric types
Fruit{:apple}
. Static dispatch works.
Benefits of enum
:
Array{Fruit}
is more efficient thanArray{AbstractFruit}
. But can useUnion{Apple, Orange, Kiwi}
.
Benefits of types:
- Static dispatch.
- Can be extended.
File System¶
Base.Filesystem.mtime
returns the modified time as a Float
. Convert to DateTime
using Dates.unix2datetime
.
Useful packages:
- NativeFileDialog.jl opens an OS file dialog.
Formatting Numbers¶
Formatting.jl
is probably the go-to package.- PrettyNumbers.jl is a smart number formatting package. It automatically prints large numbers as
1.234 x 10^3
.
Hashing¶
For new DataType
s, it is necessary to defined hash
, ==
, and isequal
. hash
is needed for containers such as Dict
s (it is used for haskey
). The way this is done can be based on AutoHashEquals.jl:
mutable struct Foo
a::Int
b
end
Base.hash(a::Foo, h::UInt) = hash(a.b, hash(a.a, hash(:Foo, h)))
Interpolation (1.6)¶
Interpolations.jl¶
One limitation: multi-dimensional interpolation only works with unform grids. The inputs must be ranges.
The default for extrapolation is to throw an error.
Example:
xV = 1:10; yV = 5:10;
zM = xV .+ yV' .+ xV .* yV';
itp = CubicInterpolation((xV, yV), zM);
itp(1.5, 5.9)
The same (?) interpolation can be constructed the long way round:
itp2 = interpolate(zM, BSpline(Cubic(Line(OnGrid()))));
sitp = scale(itp2, xV, yV);
One difference is that bounds
works on sitp
but not on itp
.
Latex Output (1.10)¶
SummaryTables.jl looks very powerful for generating fully formatted tables from DataFrames.
Latexify.jl renders various expressions as Latex equations. This is useful for automatically making expressions for functional forms. Also generates Latex tables from DataFrames
and Arrays
.
PrettyTables.jl can be used to produce Latex tables (and human readable text tables with the same content).
- set
wrap_table = false
to avoid the\begin{tabular}
block for a float.
Logging (1.6)¶
@debug
can be used to generate self-test code that is only run while developing the code.
Example:
# test1.jl
a = 1;
b = [1,2,3];
@debug begin
bSum = sum(b);
"""
Debug message
$bsum
"""
end
@debug "Debug with args:" a, b
To run this with the @debug statements enabled, issue (in the shell):
export JULIA_DEBUG=all
julia "test1.jl"
But this generates lots of debug messages that sit in Base
. To avoid this, export JULIA_DEBUG=MyPkg
.
Enabling logging levels temporarily:
lg = ConsoleLogger(stderr, Logging.Debug);
with_logger(lg) do
foo();
end
Or:
lg = ConsoleLogger(stderr, Logging.Debug);
old_logger = global_logger(lg);
foo();
global_logger(old_logger);
Random numbers (1.5)¶
Generating reproducible random numbers across Julia versions:
- This can be done with
StableRNGs.jl
. This also seems to generate the same random numbers across operating systems (in my case MacOS and Linux).
Drawing integers with given probabilities:
StatsBase.sample
does this.
RegEx¶
ReadableRegex.jl helps to construct RegEx.
Search and Find¶
searchsorted
is useful to find elements (exact matches only) in an Array.
Terminal output¶
Term.jl can do some neat things with formatted terminal output.
Writing output to stdout
and a file:
- Discourse discussion using
IOCapture.jl
Traits¶
Traits are based on the idea that functions can be dispatched statically depending on Types. The canonical example:
struct Flies end
struct DoesNotFly end
flies(x) = DoesNotFly
struct Duck end
flies(::Duck) = Flies
f(x) = f(flies(x), x)
f(::Type{Flies}, x) = "$x flies"
f(::Type{DoesNotFly}, x) = "$x walks"
d = Duck()
f(d) # Output: "Duck() flies"
f(7) # Output: "7 walks"
An interesting implementation is WhereTraits.jl which permits, for example, dispatch on functions that return Bool
.